| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <iostream> | |
| 6 #include <map> | |
| 7 #include <utility> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/command_line.h" | |
| 11 #include "base/environment.h" | |
| 12 #include "base/strings/string_number_conversions.h" | |
| 13 #include "base/timer/elapsed_timer.h" | |
| 14 #include "build/build_config.h" | |
| 15 #include "tools/gn/build_settings.h" | |
| 16 #include "tools/gn/commands.h" | |
| 17 #include "tools/gn/err.h" | |
| 18 #include "tools/gn/filesystem_utils.h" | |
| 19 #include "tools/gn/gyp_helper.h" | |
| 20 #include "tools/gn/gyp_target_writer.h" | |
| 21 #include "tools/gn/location.h" | |
| 22 #include "tools/gn/parser.h" | |
| 23 #include "tools/gn/setup.h" | |
| 24 #include "tools/gn/source_file.h" | |
| 25 #include "tools/gn/standard_out.h" | |
| 26 #include "tools/gn/target.h" | |
| 27 #include "tools/gn/tokenizer.h" | |
| 28 | |
| 29 namespace commands { | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 typedef GypTargetWriter::TargetGroup TargetGroup; | |
| 34 typedef std::map<Label, TargetGroup> CorrelatedTargetsMap; | |
| 35 typedef std::map<SourceFile, std::vector<TargetGroup> > GroupedTargetsMap; | |
| 36 typedef std::map<std::string, std::string> StringStringMap; | |
| 37 typedef std::vector<const BuilderRecord*> RecordVector; | |
| 38 | |
| 39 struct Setups { | |
| 40 Setups() | |
| 41 : debug(NULL), | |
| 42 release(NULL), | |
| 43 debug64(NULL), | |
| 44 release64(NULL), | |
| 45 xcode_debug(NULL), | |
| 46 xcode_release(NULL) { | |
| 47 } | |
| 48 | |
| 49 Setup* debug; | |
| 50 DependentSetup* release; | |
| 51 DependentSetup* debug64; | |
| 52 DependentSetup* release64; | |
| 53 DependentSetup* xcode_debug; | |
| 54 DependentSetup* xcode_release; | |
| 55 }; | |
| 56 | |
| 57 struct TargetVectors { | |
| 58 RecordVector debug; | |
| 59 RecordVector release; | |
| 60 RecordVector host_debug; | |
| 61 RecordVector host_release; | |
| 62 RecordVector debug64; | |
| 63 RecordVector release64; | |
| 64 RecordVector xcode_debug; | |
| 65 RecordVector xcode_release; | |
| 66 RecordVector xcode_host_debug; | |
| 67 RecordVector xcode_host_release; | |
| 68 }; | |
| 69 | |
| 70 // This function appends a suffix to the given source directory name. We append | |
| 71 // a suffix to the last directory component rather than adding a new level so | |
| 72 // that the relative location of the files don't change (i.e. a file | |
| 73 // relative to the build dir might be "../../foo/bar.cc") and we want these to | |
| 74 // be the same in all builds, and in particular the GYP build directories. | |
| 75 SourceDir AppendDirSuffix(const SourceDir& base, const std::string& suffix) { | |
| 76 return SourceDir(DirectoryWithNoLastSlash(base) + suffix + "/"); | |
| 77 } | |
| 78 | |
| 79 // Returns the empty label if there is no separate host build. | |
| 80 Label GetHostToolchain(const Setups& setups) { | |
| 81 const Loader* loader = setups.debug->loader(); | |
| 82 const Settings* default_settings = | |
| 83 loader->GetToolchainSettings(loader->GetDefaultToolchain()); | |
| 84 | |
| 85 // Chrome's master build config file puts the host toolchain label into the | |
| 86 // variable "host_toolchain". | |
| 87 const Value* host_value = | |
| 88 default_settings->base_config()->GetValue("host_toolchain"); | |
| 89 if (!host_value || host_value->type() != Value::STRING) | |
| 90 return Label(); | |
| 91 | |
| 92 Err err; | |
| 93 Label host_label = Label::Resolve(SourceDir(), Label(), *host_value, &err); | |
| 94 if (host_label == loader->GetDefaultToolchain()) | |
| 95 return Label(); // Host and target matches, there is no host build. | |
| 96 return host_label; | |
| 97 } | |
| 98 | |
| 99 std::vector<const BuilderRecord*> GetAllResolvedTargetRecords( | |
| 100 const Builder* builder) { | |
| 101 std::vector<const BuilderRecord*> all = builder->GetAllRecords(); | |
| 102 std::vector<const BuilderRecord*> result; | |
| 103 result.reserve(all.size()); | |
| 104 for (size_t i = 0; i < all.size(); i++) { | |
| 105 if (all[i]->type() == BuilderRecord::ITEM_TARGET && | |
| 106 all[i]->should_generate() && | |
| 107 all[i]->item()) | |
| 108 result.push_back(all[i]); | |
| 109 } | |
| 110 return result; | |
| 111 } | |
| 112 | |
| 113 // Adds all targets to the map that match the given toolchain, writing them to | |
| 114 // the given destiation vector of the record group. If toolchain is empty, it | |
| 115 // indicates the default toolchain should be matched. | |
| 116 void CorrelateRecordVector(const RecordVector& records, | |
| 117 const Label& toolchain, | |
| 118 CorrelatedTargetsMap* correlated, | |
| 119 const BuilderRecord* TargetGroup::* record_ptr) { | |
| 120 if (records.empty()) | |
| 121 return; | |
| 122 | |
| 123 Label search_toolchain = toolchain; | |
| 124 if (search_toolchain.is_null()) { | |
| 125 // Find the default toolchain. | |
| 126 search_toolchain = | |
| 127 records[0]->item()->settings()->default_toolchain_label(); | |
| 128 } | |
| 129 | |
| 130 for (size_t i = 0; i < records.size(); i++) { | |
| 131 const BuilderRecord* record = records[i]; | |
| 132 if (record->label().GetToolchainLabel() == search_toolchain) | |
| 133 (*correlated)[record->label().GetWithNoToolchain()].*record_ptr = record; | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 // Groups targets sharing the same label between debug and release. | |
| 138 // | |
| 139 // If the host toolchain is nonempty, we'll search for targets with this | |
| 140 // alternate toolchain and assign them to the corresponding "host" groups. | |
| 141 // | |
| 142 // TODO(brettw) this doesn't handle any toolchains other than the target or | |
| 143 // host ones. To support nacl, we'll need to differentiate the 32-vs-64-bit | |
| 144 // case and the default-toolchain-vs-not case. When we find a target not using | |
| 145 // hte default toolchain, we should probably just shell out to ninja. | |
| 146 void CorrelateTargets(const TargetVectors& targets, | |
| 147 const Label& host_toolchain, | |
| 148 CorrelatedTargetsMap* correlated) { | |
| 149 // Normal. | |
| 150 CorrelateRecordVector(targets.debug, Label(), correlated, | |
| 151 &TargetGroup::debug); | |
| 152 CorrelateRecordVector(targets.release, Label(), correlated, | |
| 153 &TargetGroup::release); | |
| 154 | |
| 155 // 64-bit build. | |
| 156 CorrelateRecordVector(targets.debug64, Label(), correlated, | |
| 157 &TargetGroup::debug64); | |
| 158 CorrelateRecordVector(targets.release64, Label(), correlated, | |
| 159 &TargetGroup::release64); | |
| 160 | |
| 161 // XCode build. | |
| 162 CorrelateRecordVector(targets.xcode_debug, Label(), correlated, | |
| 163 &TargetGroup::xcode_debug); | |
| 164 CorrelateRecordVector(targets.xcode_release, Label(), correlated, | |
| 165 &TargetGroup::xcode_release); | |
| 166 | |
| 167 if (!host_toolchain.is_null()) { | |
| 168 // Normal host build. | |
| 169 CorrelateRecordVector(targets.debug, host_toolchain, correlated, | |
| 170 &TargetGroup::host_debug); | |
| 171 CorrelateRecordVector(targets.release, host_toolchain, correlated, | |
| 172 &TargetGroup::host_release); | |
| 173 | |
| 174 // XCode build. | |
| 175 CorrelateRecordVector(targets.xcode_debug, host_toolchain, correlated, | |
| 176 &TargetGroup::xcode_host_debug); | |
| 177 CorrelateRecordVector(targets.xcode_release, host_toolchain, correlated, | |
| 178 &TargetGroup::xcode_host_release); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 // Verifies that both debug and release variants match. They can differ only | |
| 183 // by flags. | |
| 184 bool EnsureTargetsMatch(const TargetGroup& group, Err* err) { | |
| 185 if (!group.debug && !group.release) | |
| 186 return true; | |
| 187 | |
| 188 // Check that both debug and release made this target. | |
| 189 if (!group.debug || !group.release) { | |
| 190 const BuilderRecord* non_null_one = | |
| 191 group.debug ? group.debug : group.release; | |
| 192 *err = Err(Location(), "The debug and release builds did not both generate " | |
| 193 "a target with the name\n" + | |
| 194 non_null_one->label().GetUserVisibleName(true)); | |
| 195 return false; | |
| 196 } | |
| 197 | |
| 198 const Target* debug_target = group.debug->item()->AsTarget(); | |
| 199 const Target* release_target = group.release->item()->AsTarget(); | |
| 200 | |
| 201 // Check the flags that determine if and where we write the GYP file. | |
| 202 if (group.debug->should_generate() != group.release->should_generate() || | |
| 203 debug_target->external() != release_target->external() || | |
| 204 debug_target->gyp_file() != release_target->gyp_file()) { | |
| 205 *err = Err(Location(), "The metadata for the target\n" + | |
| 206 group.debug->label().GetUserVisibleName(true) + | |
| 207 "\ndoesn't match between the debug and release builds."); | |
| 208 return false; | |
| 209 } | |
| 210 | |
| 211 // Check that the sources match. | |
| 212 if (debug_target->sources().size() != release_target->sources().size()) { | |
| 213 *err = Err(Location(), "The source file count for the target\n" + | |
| 214 group.debug->label().GetUserVisibleName(true) + | |
| 215 "\ndoesn't have the same number of files between the debug and " | |
| 216 "release builds."); | |
| 217 return false; | |
| 218 } | |
| 219 for (size_t i = 0; i < debug_target->sources().size(); i++) { | |
| 220 if (debug_target->sources()[i] != release_target->sources()[i]) { | |
| 221 *err = Err(Location(), "The debug and release version of the target \n" + | |
| 222 group.debug->label().GetUserVisibleName(true) + | |
| 223 "\ndon't agree on the file\n" + | |
| 224 debug_target->sources()[i].value()); | |
| 225 return false; | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 // Check that the deps match. | |
| 230 if (debug_target->deps().size() != release_target->deps().size()) { | |
| 231 *err = Err(Location(), "The source file count for the target\n" + | |
| 232 group.debug->label().GetUserVisibleName(true) + | |
| 233 "\ndoesn't have the same number of deps between the debug and " | |
| 234 "release builds."); | |
| 235 return false; | |
| 236 } | |
| 237 for (size_t i = 0; i < debug_target->deps().size(); i++) { | |
| 238 if (debug_target->deps()[i].label != release_target->deps()[i].label) { | |
| 239 *err = Err(Location(), "The debug and release version of the target \n" + | |
| 240 group.debug->label().GetUserVisibleName(true) + | |
| 241 "\ndon't agree on the dep\n" + | |
| 242 debug_target->deps()[i].label.GetUserVisibleName(true)); | |
| 243 return false; | |
| 244 } | |
| 245 } | |
| 246 return true; | |
| 247 } | |
| 248 | |
| 249 // Returns the (number of targets, number of GYP files). | |
| 250 std::pair<int, int> WriteGypFiles(Setups& setups, Err* err) { | |
| 251 TargetVectors targets; | |
| 252 | |
| 253 targets.debug = GetAllResolvedTargetRecords(setups.debug->builder()); | |
| 254 targets.release = GetAllResolvedTargetRecords(setups.release->builder()); | |
| 255 | |
| 256 // 64-bit build is optional. | |
| 257 if (setups.debug64 && setups.release64) { | |
| 258 targets.debug64 = | |
| 259 GetAllResolvedTargetRecords(setups.debug64->builder()); | |
| 260 targets.release64 = | |
| 261 GetAllResolvedTargetRecords(setups.release64->builder()); | |
| 262 } | |
| 263 | |
| 264 // Xcode build is optional. | |
| 265 if (setups.xcode_debug && setups.xcode_release) { | |
| 266 targets.xcode_debug = | |
| 267 GetAllResolvedTargetRecords(setups.xcode_debug->builder()); | |
| 268 targets.xcode_release = | |
| 269 GetAllResolvedTargetRecords(setups.xcode_release->builder()); | |
| 270 } | |
| 271 | |
| 272 // Match up the debug and release version of each target by label. | |
| 273 CorrelatedTargetsMap correlated; | |
| 274 CorrelateTargets(targets, GetHostToolchain(setups), &correlated); | |
| 275 | |
| 276 GypHelper helper; | |
| 277 GroupedTargetsMap grouped_targets; | |
| 278 int target_count = 0; | |
| 279 for (CorrelatedTargetsMap::iterator i = correlated.begin(); | |
| 280 i != correlated.end(); ++i) { | |
| 281 const TargetGroup& group = i->second; | |
| 282 if (!group.get()->should_generate()) | |
| 283 continue; // Skip non-generated ones. | |
| 284 if (group.get()->item()->AsTarget()->external()) | |
| 285 continue; // Skip external ones. | |
| 286 if (group.get()->item()->AsTarget()->gyp_file().is_null()) | |
| 287 continue; // Skip ones without GYP files. | |
| 288 | |
| 289 if (!EnsureTargetsMatch(group, err)) | |
| 290 return std::make_pair(0, 0); | |
| 291 | |
| 292 target_count++; | |
| 293 grouped_targets[ | |
| 294 helper.GetGypFileForTarget(group.debug->item()->AsTarget(), err)] | |
| 295 .push_back(group); | |
| 296 if (err->has_error()) | |
| 297 return std::make_pair(0, 0); | |
| 298 } | |
| 299 | |
| 300 // Extract the toolchain for the debug targets. | |
| 301 const Toolchain* debug_toolchain = NULL; | |
| 302 if (!grouped_targets.empty()) { | |
| 303 debug_toolchain = setups.debug->builder()->GetToolchain( | |
| 304 grouped_targets.begin()->second[0].debug->item()->settings()-> | |
| 305 default_toolchain_label()); | |
| 306 } | |
| 307 | |
| 308 // Write each GYP file. | |
| 309 for (GroupedTargetsMap::iterator i = grouped_targets.begin(); | |
| 310 i != grouped_targets.end(); ++i) { | |
| 311 GypTargetWriter::WriteFile(i->first, i->second, debug_toolchain, err); | |
| 312 if (err->has_error()) | |
| 313 return std::make_pair(0, 0); | |
| 314 } | |
| 315 | |
| 316 return std::make_pair(target_count, | |
| 317 static_cast<int>(grouped_targets.size())); | |
| 318 } | |
| 319 | |
| 320 // Verifies that all build argument overrides are used by at least one of the | |
| 321 // build types. | |
| 322 void VerifyAllOverridesUsed(const Setups& setups) { | |
| 323 // Collect all declared args from all builds. | |
| 324 Scope::KeyValueMap declared; | |
| 325 setups.debug->build_settings().build_args().MergeDeclaredArguments( | |
| 326 &declared); | |
| 327 setups.release->build_settings().build_args().MergeDeclaredArguments( | |
| 328 &declared); | |
| 329 if (setups.debug64 && setups.release64) { | |
| 330 setups.debug64->build_settings().build_args().MergeDeclaredArguments( | |
| 331 &declared); | |
| 332 setups.release64->build_settings().build_args().MergeDeclaredArguments( | |
| 333 &declared); | |
| 334 } | |
| 335 if (setups.xcode_debug && setups.xcode_release) { | |
| 336 setups.xcode_debug->build_settings().build_args().MergeDeclaredArguments( | |
| 337 &declared); | |
| 338 setups.xcode_release->build_settings().build_args().MergeDeclaredArguments( | |
| 339 &declared); | |
| 340 } | |
| 341 | |
| 342 Scope::KeyValueMap used = | |
| 343 setups.debug->build_settings().build_args().GetAllOverrides(); | |
| 344 | |
| 345 Err err; | |
| 346 if (!Args::VerifyAllOverridesUsed(used, declared, &err)) { | |
| 347 // TODO(brettw) implement a system of warnings. Until we have a better | |
| 348 // system, print the error but don't cause a failure. | |
| 349 err.PrintToStdout(); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 } // namespace | |
| 354 | |
| 355 // Suppress output on success. | |
| 356 const char kSwitchQuiet[] = "q"; | |
| 357 | |
| 358 const char kGyp[] = "gyp"; | |
| 359 const char kGyp_HelpShort[] = | |
| 360 "gyp: Make GYP files from GN."; | |
| 361 const char kGyp_Help[] = | |
| 362 "gyp: Make GYP files from GN.\n" | |
| 363 "\n" | |
| 364 " This command will generate GYP files from GN sources. You can then run\n" | |
| 365 " GYP over the result to produce a build. Native GYP targets can depend\n" | |
| 366 " on any GN target except source sets. GN targets can depend on native\n" | |
| 367 " GYP targets, but all/direct dependent settings will NOT be pushed\n" | |
| 368 " across the boundary.\n" | |
| 369 "\n" | |
| 370 " To make this work you first need to manually run GN, then GYP, then\n" | |
| 371 " do the build. Because GN doesn't generate the final .ninja files,\n" | |
| 372 " there will be no rules to regenerate the .ninja files if the inputs\n" | |
| 373 " change, so you will have to manually repeat these steps each time\n" | |
| 374 " something changes:\n" | |
| 375 "\n" | |
| 376 " out/Debug/gn gyp\n" | |
| 377 " python build/gyp_chromiunm\n" | |
| 378 " ninja -C out/Debug foo_target\n" | |
| 379 "\n" | |
| 380 " Two variables are used to control how a target relates to GYP:\n" | |
| 381 "\n" | |
| 382 " - \"external != true\" and \"gyp_file\" is set: This target will be\n" | |
| 383 " written to the named GYP file in the source tree (not restricted to\n" | |
| 384 " an output or generated files directory).\n" | |
| 385 "\n" | |
| 386 " - \"external == true\" and \"gyp_file\" is set: The target will not\n" | |
| 387 " be written to a GYP file. But other targets being written to GYP\n" | |
| 388 " files can depend on it, and they will reference the given GYP file\n" | |
| 389 " name for GYP to use. This allows you to specify how GN->GYP\n" | |
| 390 " dependencies and named, and provides a place to manually set the\n" | |
| 391 " dependent configs from GYP to GN.\n" | |
| 392 "\n" | |
| 393 " - \"gyp_file\" is unset: Like the previous case, but if a GN target is\n" | |
| 394 " being written to a GYP file that depends on this one, the default\n" | |
| 395 " GYP file name will be assumed. The default name will match the name\n" | |
| 396 " of the current directory, so \"//foo/bar:baz\" would be\n" | |
| 397 " \"<(DEPTH)/foo/bar/bar.gyp:baz\".\n" | |
| 398 "\n" | |
| 399 "Switches\n" | |
| 400 " --gyp_vars\n" | |
| 401 " The GYP variables converted to a GN-style string lookup.\n" | |
| 402 " For example:\n" | |
| 403 " --gyp_vars=\"component=\\\"shared_library\\\" use_aura=\\\"1\\\"\"\n" | |
| 404 "\n" | |
| 405 "Example:\n" | |
| 406 " # This target is assumed to be in the GYP build in the file\n" | |
| 407 " # \"foo/foo.gyp\". This declaration tells GN where to find the GYP\n" | |
| 408 " # equivalent, and gives it some direct dependent settings that targets\n" | |
| 409 " # depending on it should receive (since these don't flow from GYP to\n" | |
| 410 " # GN-generated targets).\n" | |
| 411 " shared_library(\"gyp_target\") {\n" | |
| 412 " gyp_file = \"//foo/foo.gyp\"\n" | |
| 413 " external = true\n" | |
| 414 " direct_dependen_configs = [ \":gyp_target_config\" ]\n" | |
| 415 " }\n" | |
| 416 "\n" | |
| 417 " executable(\"my_app\") {\n" | |
| 418 " deps = [ \":gyp_target\" ]\n" | |
| 419 " gyp_file = \"//foo/myapp.gyp\"\n" | |
| 420 " sources = ...\n" | |
| 421 " }\n"; | |
| 422 | |
| 423 int RunGyp(const std::vector<std::string>& args) { | |
| 424 base::ElapsedTimer timer; | |
| 425 Setups setups; | |
| 426 | |
| 427 const CommandLine* cmdline = CommandLine::ForCurrentProcess(); | |
| 428 | |
| 429 // Compute output directory. | |
| 430 std::string build_dir; | |
| 431 if (args.size() == 1) { | |
| 432 build_dir = args[0]; | |
| 433 } else { | |
| 434 // Backwards-compat code for the old invocation that uses | |
| 435 // "gn gyp --output=foo" | |
| 436 // TODO(brettw) This should be removed when gyp_chromium has been updated. | |
| 437 | |
| 438 // Switch to set the build output directory. | |
| 439 const char kSwitchBuildOutput[] = "output"; | |
| 440 build_dir = cmdline->GetSwitchValueASCII(kSwitchBuildOutput); | |
| 441 if (build_dir.empty()) | |
| 442 build_dir = "//out/Default/"; | |
| 443 } | |
| 444 | |
| 445 // Deliberately leaked to avoid expensive process teardown. We also turn off | |
| 446 // unused override checking since we want to merge all declared arguments and | |
| 447 // check those, rather than check each build individually. Otherwise, you | |
| 448 // couldn't have an arg that was used in only one build type. This comes up | |
| 449 // because some args are build-type specific. | |
| 450 setups.debug = new Setup; | |
| 451 setups.debug->set_check_for_unused_overrides(false); | |
| 452 if (!setups.debug->DoSetup(build_dir)) | |
| 453 return 1; | |
| 454 const char kIsDebug[] = "is_debug"; | |
| 455 | |
| 456 SourceDir base_build_dir = setups.debug->build_settings().build_dir(); | |
| 457 setups.debug->build_settings().SetBuildDir( | |
| 458 AppendDirSuffix(base_build_dir, ".Debug")); | |
| 459 | |
| 460 // Make a release build based on the debug one. We use a new directory for | |
| 461 // the build output so that they don't stomp on each other. | |
| 462 setups.release = new DependentSetup(setups.debug); | |
| 463 setups.release->build_settings().build_args().AddArgOverride( | |
| 464 kIsDebug, Value(NULL, false)); | |
| 465 setups.release->build_settings().SetBuildDir( | |
| 466 AppendDirSuffix(base_build_dir, ".Release")); | |
| 467 | |
| 468 // 64-bit build (Windows only). | |
| 469 #if defined(OS_WIN) | |
| 470 static const char kForceWin64[] = "force_win64"; | |
| 471 setups.debug64 = new DependentSetup(setups.debug); | |
| 472 setups.debug64->build_settings().build_args().AddArgOverride( | |
| 473 kForceWin64, Value(NULL, true)); | |
| 474 setups.debug64->build_settings().SetBuildDir( | |
| 475 AppendDirSuffix(base_build_dir, ".Debug64")); | |
| 476 | |
| 477 setups.release64 = new DependentSetup(setups.release); | |
| 478 setups.release64->build_settings().build_args().AddArgOverride( | |
| 479 kForceWin64, Value(NULL, true)); | |
| 480 setups.release64->build_settings().SetBuildDir( | |
| 481 AppendDirSuffix(base_build_dir, ".Release64")); | |
| 482 #endif | |
| 483 | |
| 484 // XCode build (Mac only). | |
| 485 #if defined(OS_MACOSX) | |
| 486 static const char kGypXCode[] = "is_gyp_xcode_generator"; | |
| 487 setups.xcode_debug = new DependentSetup(setups.debug); | |
| 488 setups.xcode_debug->build_settings().build_args().AddArgOverride( | |
| 489 kGypXCode, Value(NULL, true)); | |
| 490 setups.xcode_debug->build_settings().SetBuildDir( | |
| 491 AppendDirSuffix(base_build_dir, ".XCodeDebug")); | |
| 492 | |
| 493 setups.xcode_release = new DependentSetup(setups.release); | |
| 494 setups.xcode_release->build_settings().build_args().AddArgOverride( | |
| 495 kGypXCode, Value(NULL, true)); | |
| 496 setups.xcode_release->build_settings().SetBuildDir( | |
| 497 AppendDirSuffix(base_build_dir, ".XCodeRelease")); | |
| 498 #endif | |
| 499 | |
| 500 // Run all the builds in parellel. | |
| 501 setups.release->RunPreMessageLoop(); | |
| 502 if (setups.debug64 && setups.release64) { | |
| 503 setups.debug64->RunPreMessageLoop(); | |
| 504 setups.release64->RunPreMessageLoop(); | |
| 505 } | |
| 506 if (setups.xcode_debug && setups.xcode_release) { | |
| 507 setups.xcode_debug->RunPreMessageLoop(); | |
| 508 setups.xcode_release->RunPreMessageLoop(); | |
| 509 } | |
| 510 | |
| 511 if (!setups.debug->Run()) | |
| 512 return 1; | |
| 513 | |
| 514 if (!setups.release->RunPostMessageLoop()) | |
| 515 return 1; | |
| 516 if (setups.debug64 && !setups.debug64->RunPostMessageLoop()) | |
| 517 return 1; | |
| 518 if (setups.release64 && !setups.release64->RunPostMessageLoop()) | |
| 519 return 1; | |
| 520 if (setups.xcode_debug && !setups.xcode_debug->RunPostMessageLoop()) | |
| 521 return 1; | |
| 522 if (setups.xcode_release && !setups.xcode_release->RunPostMessageLoop()) | |
| 523 return 1; | |
| 524 | |
| 525 VerifyAllOverridesUsed(setups); | |
| 526 | |
| 527 Err err; | |
| 528 std::pair<int, int> counts = WriteGypFiles(setups, &err); | |
| 529 if (err.has_error()) { | |
| 530 err.PrintToStdout(); | |
| 531 return 1; | |
| 532 } | |
| 533 | |
| 534 base::TimeDelta elapsed_time = timer.Elapsed(); | |
| 535 | |
| 536 if (!cmdline->HasSwitch(kSwitchQuiet)) { | |
| 537 OutputString("Done. ", DECORATION_GREEN); | |
| 538 | |
| 539 std::string stats = "Wrote " + | |
| 540 base::IntToString(counts.first) + " targets to " + | |
| 541 base::IntToString(counts.second) + " GYP files read from " + | |
| 542 base::IntToString( | |
| 543 setups.debug->scheduler().input_file_manager()->GetInputFileCount()) | |
| 544 + " GN files in " + | |
| 545 base::IntToString(elapsed_time.InMilliseconds()) + "ms\n"; | |
| 546 | |
| 547 OutputString(stats); | |
| 548 } | |
| 549 | |
| 550 return 0; | |
| 551 } | |
| 552 | |
| 553 } // namespace commands | |
| OLD | NEW |