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