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 <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <fstream> | 9 #include <fstream> |
10 #include <map> | 10 #include <map> |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 } | 107 } |
108 return false; | 108 return false; |
109 } | 109 } |
110 | 110 |
111 // Given an output that appears more than once, generates an error message | 111 // Given an output that appears more than once, generates an error message |
112 // that describes the problem and which targets generate it. | 112 // that describes the problem and which targets generate it. |
113 Err GetDuplicateOutputError(const std::vector<const Target*>& all_targets, | 113 Err GetDuplicateOutputError(const std::vector<const Target*>& all_targets, |
114 const OutputFile& bad_output) { | 114 const OutputFile& bad_output) { |
115 std::vector<const Target*> matches; | 115 std::vector<const Target*> matches; |
116 for (const Target* target : all_targets) { | 116 for (const Target* target : all_targets) { |
117 if (GetTargetOutputFile(target) == bad_output) | 117 for (const auto& output : target->computed_outputs()) { |
118 matches.push_back(target); | 118 if (output == bad_output) { |
| 119 matches.push_back(target); |
| 120 break; |
| 121 } |
| 122 } |
119 } | 123 } |
120 | 124 |
121 // There should always be at least two targets generating this file for this | 125 // There should always be at least two targets generating this file for this |
122 // function to be called in the first place. | 126 // function to be called in the first place. |
123 DCHECK(matches.size() >= 2); | 127 DCHECK(matches.size() >= 2); |
124 std::string matches_string; | 128 std::string matches_string; |
125 for (const Target* target : matches) | 129 for (const Target* target : matches) |
126 matches_string += " " + target->label().GetUserVisibleName(false) + "\n"; | 130 matches_string += " " + target->label().GetUserVisibleName(false) + "\n"; |
127 | 131 |
128 Err result(matches[0]->defined_from(), "Duplicate output file.", | 132 Err result(matches[0]->defined_from(), "Duplicate output file.", |
129 "Two or more targets generate the same output:\n " + | 133 "Two or more targets generate the same output:\n " + |
130 bad_output.value() + "\n" | 134 bad_output.value() + "\n\n" |
131 "This is normally the result of either overriding the output name or\n" | 135 "This is can often be fixed by changing one of the target names, or by \n" |
132 "having two shared libraries or executables in different directories\n" | 136 "setting an output_name on one of them.\n" |
133 "with the same name (since all such targets will be written to the root\n" | 137 "\nCollisions:\n" + matches_string); |
134 "output directory).\n\nCollisions:\n" + matches_string); | |
135 for (size_t i = 1; i < matches.size(); i++) | 138 for (size_t i = 1; i < matches.size(); i++) |
136 result.AppendSubErr(Err(matches[i]->defined_from(), "Collision.")); | 139 result.AppendSubErr(Err(matches[i]->defined_from(), "Collision.")); |
137 return result; | 140 return result; |
138 } | 141 } |
139 | 142 |
140 } // namespace | 143 } // namespace |
141 | 144 |
142 NinjaBuildWriter::NinjaBuildWriter( | 145 NinjaBuildWriter::NinjaBuildWriter( |
143 const BuildSettings* build_settings, | 146 const BuildSettings* build_settings, |
144 const std::vector<const Settings*>& all_settings, | 147 const std::vector<const Settings*>& all_settings, |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 | 290 |
288 // Add the files to the list of generated targets so we don't write phony | 291 // Add the files to the list of generated targets so we don't write phony |
289 // rules that collide. | 292 // rules that collide. |
290 std::string target_file(target->dependency_output_file().value()); | 293 std::string target_file(target->dependency_output_file().value()); |
291 NormalizePath(&target_file); | 294 NormalizePath(&target_file); |
292 written_rules.insert(target_file); | 295 written_rules.insert(target_file); |
293 } | 296 } |
294 | 297 |
295 for (const auto& target : default_toolchain_targets_) { | 298 for (const auto& target : default_toolchain_targets_) { |
296 const Label& label = target->label(); | 299 const Label& label = target->label(); |
297 OutputFile target_file = GetTargetOutputFile(target); | 300 for (const auto& output : target->computed_outputs()) { |
298 if (!target_files.insert(target_file.value()).second) { | 301 if (!target_files.insert(output.value()).second) { |
299 *err = GetDuplicateOutputError(default_toolchain_targets_, target_file); | 302 *err = GetDuplicateOutputError(default_toolchain_targets_, output); |
300 return false; | 303 return false; |
| 304 } |
301 } | 305 } |
302 | 306 |
| 307 OutputFile target_file = GetTargetOutputFile(target); |
303 // Write the long name "foo/bar:baz" for the target "//foo/bar:baz". | 308 // Write the long name "foo/bar:baz" for the target "//foo/bar:baz". |
304 std::string long_name = label.GetUserVisibleName(false); | 309 std::string long_name = label.GetUserVisibleName(false); |
305 base::TrimString(long_name, "/", &long_name); | 310 base::TrimString(long_name, "/", &long_name); |
306 WritePhonyRule(target, target_file, long_name, &written_rules); | 311 WritePhonyRule(target, target_file, long_name, &written_rules); |
307 | 312 |
308 // Write the directory name with no target name if they match | 313 // Write the directory name with no target name if they match |
309 // (e.g. "//foo/bar:bar" -> "foo/bar"). | 314 // (e.g. "//foo/bar:bar" -> "foo/bar"). |
310 if (FindLastDirComponent(label.dir()) == label.name()) { | 315 if (FindLastDirComponent(label.dir()) == label.name()) { |
311 std::string medium_name = DirectoryWithNoLastSlash(label.dir()); | 316 std::string medium_name = DirectoryWithNoLastSlash(label.dir()); |
312 base::TrimString(medium_name, "/", &medium_name); | 317 base::TrimString(medium_name, "/", &medium_name); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 EscapeOptions ninja_escape; | 397 EscapeOptions ninja_escape; |
393 ninja_escape.mode = ESCAPE_NINJA; | 398 ninja_escape.mode = ESCAPE_NINJA; |
394 | 399 |
395 // Escape for special chars Ninja will handle. | 400 // Escape for special chars Ninja will handle. |
396 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); | 401 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); |
397 | 402 |
398 out_ << "build " << escaped << ": phony "; | 403 out_ << "build " << escaped << ": phony "; |
399 path_output_.WriteFile(out_, target_file); | 404 path_output_.WriteFile(out_, target_file); |
400 out_ << std::endl; | 405 out_ << std::endl; |
401 } | 406 } |
OLD | NEW |