OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/atomicops.h" | 5 #include "base/atomicops.h" |
6 #include "base/bind.h" | 6 #include "base/bind.h" |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
10 #include "base/timer/elapsed_timer.h" | 10 #include "base/timer/elapsed_timer.h" |
(...skipping 28 matching lines...) Expand all Loading... |
39 const char kSwitchIdeValueXcode[] = "xcode"; | 39 const char kSwitchIdeValueXcode[] = "xcode"; |
40 const char kSwitchIdeValueJson[] = "json"; | 40 const char kSwitchIdeValueJson[] = "json"; |
41 const char kSwitchNinjaExtraArgs[] = "ninja-extra-args"; | 41 const char kSwitchNinjaExtraArgs[] = "ninja-extra-args"; |
42 const char kSwitchRootTarget[] = "root-target"; | 42 const char kSwitchRootTarget[] = "root-target"; |
43 const char kSwitchSln[] = "sln"; | 43 const char kSwitchSln[] = "sln"; |
44 const char kSwitchWorkspace[] = "workspace"; | 44 const char kSwitchWorkspace[] = "workspace"; |
45 const char kSwitchJsonFileName[] = "json-file-name"; | 45 const char kSwitchJsonFileName[] = "json-file-name"; |
46 const char kSwitchJsonIdeScript[] = "json-ide-script"; | 46 const char kSwitchJsonIdeScript[] = "json-ide-script"; |
47 const char kSwitchJsonIdeScriptArgs[] = "json-ide-script-args"; | 47 const char kSwitchJsonIdeScriptArgs[] = "json-ide-script-args"; |
48 | 48 |
| 49 // Collects Ninja rules for each toolchain. The lock protectes the rules. |
| 50 struct TargetWriteInfo { |
| 51 base::Lock lock; |
| 52 NinjaWriter::PerToolchainRules rules; |
| 53 }; |
| 54 |
49 // Called on worker thread to write the ninja file. | 55 // Called on worker thread to write the ninja file. |
50 void BackgroundDoWrite(const Target* target) { | 56 void BackgroundDoWrite(TargetWriteInfo* write_info, const Target* target) { |
51 NinjaTargetWriter::RunAndWriteFile(target); | 57 std::string rule = NinjaTargetWriter::RunAndWriteFile(target); |
| 58 DCHECK(!rule.empty()); |
| 59 |
| 60 { |
| 61 base::AutoLock lock(write_info->lock); |
| 62 write_info->rules[target->toolchain()].emplace_back( |
| 63 target, std::move(rule)); |
| 64 } |
| 65 |
52 g_scheduler->DecrementWorkCount(); | 66 g_scheduler->DecrementWorkCount(); |
53 } | 67 } |
54 | 68 |
55 // Called on the main thread. | 69 // Called on the main thread. |
56 void ItemResolvedCallback(base::subtle::Atomic32* write_counter, | 70 void ItemResolvedCallback(TargetWriteInfo* write_info, |
57 scoped_refptr<Builder> builder, | |
58 const BuilderRecord* record) { | 71 const BuilderRecord* record) { |
59 base::subtle::NoBarrier_AtomicIncrement(write_counter, 1); | |
60 | |
61 const Item* item = record->item(); | 72 const Item* item = record->item(); |
62 const Target* target = item->AsTarget(); | 73 const Target* target = item->AsTarget(); |
63 if (target) { | 74 if (target) { |
64 g_scheduler->IncrementWorkCount(); | 75 g_scheduler->IncrementWorkCount(); |
65 g_scheduler->ScheduleWork(base::Bind(&BackgroundDoWrite, target)); | 76 g_scheduler->ScheduleWork(base::Bind(&BackgroundDoWrite, |
| 77 write_info, target)); |
66 } | 78 } |
67 } | 79 } |
68 | 80 |
69 // Returns a pointer to the target with the given file as an output, or null | 81 // Returns a pointer to the target with the given file as an output, or null |
70 // if no targets generate the file. This is brute force since this is an | 82 // if no targets generate the file. This is brute force since this is an |
71 // error condition and performance shouldn't matter. | 83 // error condition and performance shouldn't matter. |
72 const Target* FindTargetThatGeneratesFile(const Builder* builder, | 84 const Target* FindTargetThatGeneratesFile(const Builder& builder, |
73 const SourceFile& file) { | 85 const SourceFile& file) { |
74 std::vector<const Target*> targets = builder->GetAllResolvedTargets(); | 86 std::vector<const Target*> targets = builder.GetAllResolvedTargets(); |
75 if (targets.empty()) | 87 if (targets.empty()) |
76 return nullptr; | 88 return nullptr; |
77 | 89 |
78 OutputFile output_file(targets[0]->settings()->build_settings(), file); | 90 OutputFile output_file(targets[0]->settings()->build_settings(), file); |
79 for (const Target* target : targets) { | 91 for (const Target* target : targets) { |
80 for (const auto& cur_output : target->computed_outputs()) { | 92 for (const auto& cur_output : target->computed_outputs()) { |
81 if (cur_output == output_file) | 93 if (cur_output == output_file) |
82 return target; | 94 return target; |
83 } | 95 } |
84 } | 96 } |
85 return nullptr; | 97 return nullptr; |
86 } | 98 } |
87 | 99 |
88 // Prints an error that the given file was present as a source or input in | 100 // Prints an error that the given file was present as a source or input in |
89 // the given target(s) but was not generated by any of its dependencies. | 101 // the given target(s) but was not generated by any of its dependencies. |
90 void PrintInvalidGeneratedInput(const Builder* builder, | 102 void PrintInvalidGeneratedInput(const Builder& builder, |
91 const SourceFile& file, | 103 const SourceFile& file, |
92 const std::vector<const Target*>& targets) { | 104 const std::vector<const Target*>& targets) { |
93 std::string err; | 105 std::string err; |
94 | 106 |
95 // Only show the toolchain labels (which can be confusing) if something | 107 // Only show the toolchain labels (which can be confusing) if something |
96 // isn't the default. | 108 // isn't the default. |
97 bool show_toolchains = false; | 109 bool show_toolchains = false; |
98 const Label& default_toolchain = | 110 const Label& default_toolchain = |
99 targets[0]->settings()->default_toolchain_label(); | 111 targets[0]->settings()->default_toolchain_label(); |
100 for (const Target* target : targets) { | 112 for (const Target* target : targets) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 | 172 |
161 if (errors_found > 1) { | 173 if (errors_found > 1) { |
162 OutputString(base::StringPrintf("\n%d generated input errors found.\n", | 174 OutputString(base::StringPrintf("\n%d generated input errors found.\n", |
163 errors_found), DECORATION_YELLOW); | 175 errors_found), DECORATION_YELLOW); |
164 } | 176 } |
165 return false; | 177 return false; |
166 } | 178 } |
167 | 179 |
168 bool RunIdeWriter(const std::string& ide, | 180 bool RunIdeWriter(const std::string& ide, |
169 const BuildSettings* build_settings, | 181 const BuildSettings* build_settings, |
170 Builder* builder, | 182 const Builder& builder, |
171 Err* err) { | 183 Err* err) { |
172 const base::CommandLine* command_line = | 184 const base::CommandLine* command_line = |
173 base::CommandLine::ForCurrentProcess(); | 185 base::CommandLine::ForCurrentProcess(); |
174 bool quiet = command_line->HasSwitch(switches::kQuiet); | 186 bool quiet = command_line->HasSwitch(switches::kQuiet); |
175 base::ElapsedTimer timer; | 187 base::ElapsedTimer timer; |
176 | 188 |
177 if (ide == kSwitchIdeValueEclipse) { | 189 if (ide == kSwitchIdeValueEclipse) { |
178 bool res = EclipseWriter::RunAndWriteFile(build_settings, builder, err); | 190 bool res = EclipseWriter::RunAndWriteFile(build_settings, builder, err); |
179 if (res && !quiet) { | 191 if (res && !quiet) { |
180 OutputString("Generating Eclipse settings took " + | 192 OutputString("Generating Eclipse settings took " + |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 // Deliberately leaked to avoid expensive process teardown. | 378 // Deliberately leaked to avoid expensive process teardown. |
367 Setup* setup = new Setup(); | 379 Setup* setup = new Setup(); |
368 if (!setup->DoSetup(args[0], true)) | 380 if (!setup->DoSetup(args[0], true)) |
369 return 1; | 381 return 1; |
370 | 382 |
371 const base::CommandLine* command_line = | 383 const base::CommandLine* command_line = |
372 base::CommandLine::ForCurrentProcess(); | 384 base::CommandLine::ForCurrentProcess(); |
373 if (command_line->HasSwitch(kSwitchCheck)) | 385 if (command_line->HasSwitch(kSwitchCheck)) |
374 setup->set_check_public_headers(true); | 386 setup->set_check_public_headers(true); |
375 | 387 |
376 // Cause the load to also generate the ninja files for each target. We wrap | 388 // Cause the load to also generate the ninja files for each target. |
377 // the writing to maintain a counter. | 389 TargetWriteInfo write_info; |
378 base::subtle::Atomic32 write_counter = 0; | 390 setup->builder().set_resolved_callback( |
379 setup->builder()->set_resolved_callback( | 391 base::Bind(&ItemResolvedCallback, &write_info)); |
380 base::Bind(&ItemResolvedCallback, &write_counter, | |
381 scoped_refptr<Builder>(setup->builder()))); | |
382 | 392 |
383 // Do the actual load. This will also write out the target ninja files. | 393 // Do the actual load. This will also write out the target ninja files. |
384 if (!setup->Run()) | 394 if (!setup->Run()) |
385 return 1; | 395 return 1; |
386 | 396 |
| 397 // Sort the targets in each toolchain according to their label. This makes |
| 398 // the ninja files have deterministic content. |
| 399 for (auto& cur_toolchain : write_info.rules) { |
| 400 std::sort(cur_toolchain.second.begin(), cur_toolchain.second.end(), |
| 401 [](const NinjaWriter::TargetRulePair& a, |
| 402 const NinjaWriter::TargetRulePair& b) { |
| 403 return a.first->label() < b.first->label(); |
| 404 }); |
| 405 } |
| 406 |
387 Err err; | 407 Err err; |
388 // Write the root ninja files. | 408 // Write the root ninja files. |
389 if (!NinjaWriter::RunAndWriteFiles(&setup->build_settings(), | 409 if (!NinjaWriter::RunAndWriteFiles(&setup->build_settings(), |
390 setup->builder(), | 410 setup->builder(), |
| 411 write_info.rules, |
391 &err)) { | 412 &err)) { |
392 err.PrintToStdout(); | 413 err.PrintToStdout(); |
393 return 1; | 414 return 1; |
394 } | 415 } |
395 | 416 |
396 if (!WriteRuntimeDepsFilesIfNecessary(*setup->builder(), &err)) { | 417 if (!WriteRuntimeDepsFilesIfNecessary(setup->builder(), &err)) { |
397 err.PrintToStdout(); | 418 err.PrintToStdout(); |
398 return 1; | 419 return 1; |
399 } | 420 } |
400 | 421 |
401 if (!CheckForInvalidGeneratedInputs(setup)) | 422 if (!CheckForInvalidGeneratedInputs(setup)) |
402 return 1; | 423 return 1; |
403 | 424 |
404 if (command_line->HasSwitch(kSwitchIde) && | 425 if (command_line->HasSwitch(kSwitchIde) && |
405 !RunIdeWriter(command_line->GetSwitchValueASCII(kSwitchIde), | 426 !RunIdeWriter(command_line->GetSwitchValueASCII(kSwitchIde), |
406 &setup->build_settings(), setup->builder(), &err)) { | 427 &setup->build_settings(), setup->builder(), &err)) { |
407 err.PrintToStdout(); | 428 err.PrintToStdout(); |
408 return 1; | 429 return 1; |
409 } | 430 } |
410 | 431 |
411 base::TimeDelta elapsed_time = timer.Elapsed(); | 432 base::TimeDelta elapsed_time = timer.Elapsed(); |
412 | 433 |
413 if (!command_line->HasSwitch(switches::kQuiet)) { | 434 if (!command_line->HasSwitch(switches::kQuiet)) { |
414 OutputString("Done. ", DECORATION_GREEN); | 435 OutputString("Done. ", DECORATION_GREEN); |
415 | 436 |
416 std::string stats = "Wrote " + | 437 size_t targets_collected = 0; |
417 base::IntToString(static_cast<int>(write_counter)) + | 438 for (const auto& rules : write_info.rules) |
| 439 targets_collected += rules.second.size(); |
| 440 |
| 441 std::string stats = "Made " + base::SizeTToString(targets_collected) + |
418 " targets from " + | 442 " targets from " + |
419 base::IntToString( | 443 base::IntToString( |
420 setup->scheduler().input_file_manager()->GetInputFileCount()) + | 444 setup->scheduler().input_file_manager()->GetInputFileCount()) + |
421 " files in " + | 445 " files in " + |
422 base::Int64ToString(elapsed_time.InMilliseconds()) + "ms\n"; | 446 base::Int64ToString(elapsed_time.InMilliseconds()) + "ms\n"; |
423 OutputString(stats); | 447 OutputString(stats); |
424 } | 448 } |
425 | 449 |
426 return 0; | 450 return 0; |
427 } | 451 } |
428 | 452 |
429 } // namespace commands | 453 } // namespace commands |
OLD | NEW |