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 "tools/gn/ninja_build_writer.h" | 5 #include "tools/gn/ninja_build_writer.h" |
6 | 6 |
7 #include <fstream> | 7 #include <fstream> |
8 #include <map> | 8 #include <map> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 } | 78 } |
79 | 79 |
80 OutputFile GetTargetOutputFile(const Target* target) { | 80 OutputFile GetTargetOutputFile(const Target* target) { |
81 OutputFile result(target->dependency_output_file()); | 81 OutputFile result(target->dependency_output_file()); |
82 | 82 |
83 // The output files may have leading "./" so normalize those away. | 83 // The output files may have leading "./" so normalize those away. |
84 NormalizePath(&result.value()); | 84 NormalizePath(&result.value()); |
85 return result; | 85 return result; |
86 } | 86 } |
87 | 87 |
| 88 bool HasOutputIdenticalToLabel(const Target* target, |
| 89 const std::string& short_name) { |
| 90 if (target->output_type() != Target::ACTION && |
| 91 target->output_type() != Target::ACTION_FOREACH) |
| 92 return false; |
| 93 |
| 94 // Rather than convert all outputs to be relative to the build directory |
| 95 // and then compare to the short name, convert the short name to look like a |
| 96 // file in the output directory since this is only one conversion. |
| 97 SourceFile short_name_as_source_file( |
| 98 target->settings()->build_settings()->build_dir().value() + short_name); |
| 99 |
| 100 std::vector<SourceFile> outputs_as_source; |
| 101 target->action_values().GetOutputsAsSourceFiles(target, &outputs_as_source); |
| 102 for (const SourceFile& output_as_source : outputs_as_source) { |
| 103 if (output_as_source == short_name_as_source_file) |
| 104 return true; |
| 105 } |
| 106 return false; |
| 107 } |
| 108 |
88 // Given an output that appears more than once, generates an error message | 109 // Given an output that appears more than once, generates an error message |
89 // that describes the problem and which targets generate it. | 110 // that describes the problem and which targets generate it. |
90 Err GetDuplicateOutputError(const std::vector<const Target*>& all_targets, | 111 Err GetDuplicateOutputError(const std::vector<const Target*>& all_targets, |
91 const OutputFile& bad_output) { | 112 const OutputFile& bad_output) { |
92 std::vector<const Target*> matches; | 113 std::vector<const Target*> matches; |
93 for (const Target* target : all_targets) { | 114 for (const Target* target : all_targets) { |
94 if (GetTargetOutputFile(target) == bad_output) | 115 if (GetTargetOutputFile(target) == bad_output) |
95 matches.push_back(target); | 116 matches.push_back(target); |
96 } | 117 } |
97 | 118 |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 // target which we already wrote. | 308 // target which we already wrote. |
288 if (medium_name != label.name()) | 309 if (medium_name != label.name()) |
289 WritePhonyRule(target, target_file, medium_name, &written_rules); | 310 WritePhonyRule(target, target_file, medium_name, &written_rules); |
290 } | 311 } |
291 | 312 |
292 // Write short names for ones which are either completely unique or there | 313 // Write short names for ones which are either completely unique or there |
293 // at least only one of them in the default toolchain that is an exe. | 314 // at least only one of them in the default toolchain that is an exe. |
294 if (small_name_count[label.name()] == 1 || | 315 if (small_name_count[label.name()] == 1 || |
295 (target->output_type() == Target::EXECUTABLE && | 316 (target->output_type() == Target::EXECUTABLE && |
296 exe_count[label.name()] == 1)) { | 317 exe_count[label.name()] == 1)) { |
297 WritePhonyRule(target, target_file, label.name(), &written_rules); | 318 // It's reasonable to generate output files in the root build directory |
| 319 // with the same name as the target. Don't generate phony rules for |
| 320 // these cases. |
| 321 // |
| 322 // All of this does not do the general checking of all target's outputs |
| 323 // which may theoretically collide. But it's not very reasonable for |
| 324 // a script target named "foo" to generate a file named "bar" with no |
| 325 // extension in the root build directory while another target is named |
| 326 // "bar". If this does occur, the user is likely to be confused when |
| 327 // building "bar" that is builds foo anyway, so you probably just |
| 328 // shouldn't do that. |
| 329 // |
| 330 // We should fix this however, and build up all generated script outputs |
| 331 // and check everything against that. There are other edge cases that the |
| 332 // current phony rule generator doesn't check. We may need to make a big |
| 333 // set of every possible generated file in the build for this purpose. |
| 334 if (!HasOutputIdenticalToLabel(target, label.name())) |
| 335 WritePhonyRule(target, target_file, label.name(), &written_rules); |
298 } | 336 } |
299 | 337 |
300 if (!all_rules.empty()) | 338 if (!all_rules.empty()) |
301 all_rules.append(" $\n "); | 339 all_rules.append(" $\n "); |
302 all_rules.append(target_file.value()); | 340 all_rules.append(target_file.value()); |
303 } | 341 } |
304 | 342 |
305 // Pick up phony rules for the toplevel targets with non-unique names (which | 343 // Pick up phony rules for the toplevel targets with non-unique names (which |
306 // would have been skipped in the above loop). | 344 // would have been skipped in the above loop). |
307 for (const auto& toplevel_target : toplevel_targets) { | 345 for (const auto& toplevel_target : toplevel_targets) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 EscapeOptions ninja_escape; | 386 EscapeOptions ninja_escape; |
349 ninja_escape.mode = ESCAPE_NINJA; | 387 ninja_escape.mode = ESCAPE_NINJA; |
350 | 388 |
351 // Escape for special chars Ninja will handle. | 389 // Escape for special chars Ninja will handle. |
352 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); | 390 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); |
353 | 391 |
354 out_ << "build " << escaped << ": phony "; | 392 out_ << "build " << escaped << ": phony "; |
355 path_output_.WriteFile(out_, target_file); | 393 path_output_.WriteFile(out_, target_file); |
356 out_ << std::endl; | 394 out_ << std::endl; |
357 } | 395 } |
OLD | NEW |