| Index: tools/gn/ninja_build_writer.cc
|
| diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
|
| index 248a45a2a674f1b58bf340790639ad18e896179c..591947d38cae9ca29918c11fc7697625fd56a229 100644
|
| --- a/tools/gn/ninja_build_writer.cc
|
| +++ b/tools/gn/ninja_build_writer.cc
|
| @@ -186,6 +186,12 @@ void NinjaBuildWriter::WriteSubninjas() {
|
| bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
|
| std::string all_rules;
|
|
|
| + // Track rules as we generate them so we don't accidentally write a phony
|
| + // rule that collides with something else.
|
| + // GN internally generates an "all" target, so don't duplicate it.
|
| + std::set<std::string> written_rules;
|
| + written_rules.insert("all");
|
| +
|
| // Write phony rules for all uniquely-named targets in the default toolchain.
|
| // Don't do other toolchains or we'll get naming conflicts, and if the name
|
| // isn't unique, also skip it. The exception is for the toplevel targets
|
| @@ -214,6 +220,12 @@ bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
|
| // even if there are non-executable targets with the same name.
|
| if (target->output_type() == Target::EXECUTABLE)
|
| exe_count[label.name()]++;
|
| +
|
| + // Add the files to the list of generated targets so we don't write phony
|
| + // rules that collide.
|
| + std::string target_file(target->dependency_output_file().value());
|
| + NormalizePath(&target_file);
|
| + written_rules.insert(target_file);
|
| }
|
|
|
| for (const auto& target : default_toolchain_targets_) {
|
| @@ -229,7 +241,7 @@ bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
|
| // Write the long name "foo/bar:baz" for the target "//foo/bar:baz".
|
| std::string long_name = label.GetUserVisibleName(false);
|
| base::TrimString(long_name, "/", &long_name);
|
| - WritePhonyRule(target, target_file, long_name);
|
| + WritePhonyRule(target, target_file, long_name, &written_rules);
|
|
|
| // Write the directory name with no target name if they match
|
| // (e.g. "//foo/bar:bar" -> "foo/bar").
|
| @@ -239,7 +251,7 @@ bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
|
| // That may have generated a name the same as the short name of the
|
| // target which we already wrote.
|
| if (medium_name != label.name())
|
| - WritePhonyRule(target, target_file, medium_name);
|
| + WritePhonyRule(target, target_file, medium_name, &written_rules);
|
| }
|
|
|
| // Write short names for ones which are either completely unique or there
|
| @@ -247,7 +259,7 @@ bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
|
| if (small_name_count[label.name()] == 1 ||
|
| (target->output_type() == Target::EXECUTABLE &&
|
| exe_count[label.name()] == 1)) {
|
| - WritePhonyRule(target, target_file, label.name());
|
| + WritePhonyRule(target, target_file, label.name(), &written_rules);
|
| }
|
|
|
| if (!all_rules.empty())
|
| @@ -260,7 +272,7 @@ bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
|
| for (const auto& toplevel_target : toplevel_targets) {
|
| if (small_name_count[toplevel_target->label().name()] > 1) {
|
| WritePhonyRule(toplevel_target, toplevel_target->dependency_output_file(),
|
| - toplevel_target->label().name());
|
| + toplevel_target->label().name(), &written_rules);
|
| }
|
| }
|
|
|
| @@ -289,10 +301,15 @@ bool NinjaBuildWriter::WritePhonyAndAllRules(Err* err) {
|
|
|
| void NinjaBuildWriter::WritePhonyRule(const Target* target,
|
| const OutputFile& target_file,
|
| - const std::string& phony_name) {
|
| + const std::string& phony_name,
|
| + std::set<std::string>* written_rules) {
|
| if (target_file.value() == phony_name)
|
| return; // No need for a phony rule.
|
|
|
| + if (written_rules->find(phony_name) != written_rules->end())
|
| + return; // Already exists.
|
| + written_rules->insert(phony_name);
|
| +
|
| EscapeOptions ninja_escape;
|
| ninja_escape.mode = ESCAPE_NINJA;
|
|
|
|
|