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 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 } | 184 } |
185 | 185 |
186 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) { | 186 bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) { |
187 std::string all_rules; | 187 std::string all_rules; |
188 | 188 |
189 // Write phony rules for all uniquely-named targets in the default toolchain. | 189 // Write phony rules for all uniquely-named targets in the default toolchain. |
190 // Don't do other toolchains or we'll get naming conflicts, and if the name | 190 // Don't do other toolchains or we'll get naming conflicts, and if the name |
191 // isn't unique, also skip it. The exception is for the toplevel targets | 191 // isn't unique, also skip it. The exception is for the toplevel targets |
192 // which we also find. | 192 // which we also find. |
193 std::map<std::string, int> small_name_count; | 193 std::map<std::string, int> small_name_count; |
| 194 std::map<std::string, int> exe_count; |
194 std::vector<const Target*> toplevel_targets; | 195 std::vector<const Target*> toplevel_targets; |
195 base::hash_set<std::string> target_files; | 196 base::hash_set<std::string> target_files; |
196 for (const auto& target : default_toolchain_targets_) { | 197 for (const auto& target : default_toolchain_targets_) { |
197 const Label& label = target->label(); | 198 const Label& label = target->label(); |
198 small_name_count[label.name()]++; | 199 small_name_count[label.name()]++; |
199 | 200 |
200 // Look for targets with a name of the form | 201 // Look for targets with a name of the form |
201 // dir = "//foo/", name = "foo" | 202 // dir = "//foo/", name = "foo" |
202 // i.e. where the target name matches the top level directory. We will | 203 // i.e. where the target name matches the top level directory. We will |
203 // always write phony rules for these even if there is another target with | 204 // always write phony rules for these even if there is another target with |
204 // the same short name. | 205 // the same short name. |
205 const std::string& dir_string = label.dir().value(); | 206 const std::string& dir_string = label.dir().value(); |
206 if (dir_string.size() == label.name().size() + 3 && // Size matches. | 207 if (dir_string.size() == label.name().size() + 3 && // Size matches. |
207 dir_string[0] == '/' && dir_string[1] == '/' && // "//" at beginning. | 208 dir_string[0] == '/' && dir_string[1] == '/' && // "//" at beginning. |
208 dir_string[dir_string.size() - 1] == '/' && // "/" at end. | 209 dir_string[dir_string.size() - 1] == '/' && // "/" at end. |
209 dir_string.compare(2, label.name().size(), label.name()) == 0) | 210 dir_string.compare(2, label.name().size(), label.name()) == 0) |
210 toplevel_targets.push_back(target); | 211 toplevel_targets.push_back(target); |
| 212 |
| 213 // Look for executables; later we will generate phony rules for them |
| 214 // even if there are non-executable targets with the same name. |
| 215 if (target->output_type() == Target::EXECUTABLE) |
| 216 exe_count[label.name()]++; |
211 } | 217 } |
212 | 218 |
213 for (const auto& target : default_toolchain_targets_) { | 219 for (const auto& target : default_toolchain_targets_) { |
214 const Label& label = target->label(); | 220 const Label& label = target->label(); |
215 OutputFile target_file(target->dependency_output_file()); | 221 OutputFile target_file(target->dependency_output_file()); |
216 // The output files may have leading "./" so normalize those away. | 222 // The output files may have leading "./" so normalize those away. |
217 NormalizePath(&target_file.value()); | 223 NormalizePath(&target_file.value()); |
218 if (!target_files.insert(target_file.value()).second) { | 224 if (!target_files.insert(target_file.value()).second) { |
219 *err = Err(Location(), "Duplicate rules for " + target_file.value()); | 225 *err = Err(Location(), "Duplicate rules for " + target_file.value()); |
220 return false; | 226 return false; |
221 } | 227 } |
222 | 228 |
223 // Write the long name "foo/bar:baz" for the target "//foo/bar:baz". | 229 // Write the long name "foo/bar:baz" for the target "//foo/bar:baz". |
224 std::string long_name = label.GetUserVisibleName(false); | 230 std::string long_name = label.GetUserVisibleName(false); |
225 base::TrimString(long_name, "/", &long_name); | 231 base::TrimString(long_name, "/", &long_name); |
226 WritePhonyRule(target, target_file, long_name); | 232 WritePhonyRule(target, target_file, long_name); |
227 | 233 |
228 // Write the directory name with no target name if they match | 234 // Write the directory name with no target name if they match |
229 // (e.g. "//foo/bar:bar" -> "foo/bar"). | 235 // (e.g. "//foo/bar:bar" -> "foo/bar"). |
230 if (FindLastDirComponent(label.dir()) == label.name()) { | 236 if (FindLastDirComponent(label.dir()) == label.name()) { |
231 std::string medium_name = DirectoryWithNoLastSlash(label.dir()); | 237 std::string medium_name = DirectoryWithNoLastSlash(label.dir()); |
232 base::TrimString(medium_name, "/", &medium_name); | 238 base::TrimString(medium_name, "/", &medium_name); |
233 // That may have generated a name the same as the short name of the | 239 // That may have generated a name the same as the short name of the |
234 // target which we already wrote. | 240 // target which we already wrote. |
235 if (medium_name != label.name()) | 241 if (medium_name != label.name()) |
236 WritePhonyRule(target, target_file, medium_name); | 242 WritePhonyRule(target, target_file, medium_name); |
237 } | 243 } |
238 | 244 |
239 // Write short names for ones which are unique. | 245 // Write short names for ones which are either completely unique or there |
240 if (small_name_count[label.name()] == 1) | 246 // at least only one of them in the default toolchain that is an exe. |
| 247 if (small_name_count[label.name()] == 1 || |
| 248 (target->output_type() == Target::EXECUTABLE && |
| 249 exe_count[label.name()] == 1)) { |
241 WritePhonyRule(target, target_file, label.name()); | 250 WritePhonyRule(target, target_file, label.name()); |
| 251 } |
242 | 252 |
243 if (!all_rules.empty()) | 253 if (!all_rules.empty()) |
244 all_rules.append(" $\n "); | 254 all_rules.append(" $\n "); |
245 all_rules.append(target_file.value()); | 255 all_rules.append(target_file.value()); |
246 } | 256 } |
247 | 257 |
248 // Pick up phony rules for the toplevel targets with non-unique names (which | 258 // Pick up phony rules for the toplevel targets with non-unique names (which |
249 // would have been skipped in the above loop). | 259 // would have been skipped in the above loop). |
250 for (const auto& toplevel_target : toplevel_targets) { | 260 for (const auto& toplevel_target : toplevel_targets) { |
251 if (small_name_count[toplevel_target->label().name()] > 1) { | 261 if (small_name_count[toplevel_target->label().name()] > 1) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 EscapeOptions ninja_escape; | 296 EscapeOptions ninja_escape; |
287 ninja_escape.mode = ESCAPE_NINJA; | 297 ninja_escape.mode = ESCAPE_NINJA; |
288 | 298 |
289 // Escape for special chars Ninja will handle. | 299 // Escape for special chars Ninja will handle. |
290 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); | 300 std::string escaped = EscapeString(phony_name, ninja_escape, nullptr); |
291 | 301 |
292 out_ << "build " << escaped << ": phony "; | 302 out_ << "build " << escaped << ": phony "; |
293 path_output_.WriteFile(out_, target_file); | 303 path_output_.WriteFile(out_, target_file); |
294 out_ << std::endl; | 304 out_ << std::endl; |
295 } | 305 } |
OLD | NEW |