| 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 |