| Index: tools/gn/ninja_build_writer.cc
|
| diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
|
| index 11b36e6b591e74a85753f2998aad2dcfe003dc36..c0fc7fcfedfd9667c26de0984cf2fca47c7f92d1 100644
|
| --- a/tools/gn/ninja_build_writer.cc
|
| +++ b/tools/gn/ninja_build_writer.cc
|
| @@ -11,6 +11,7 @@
|
| #include "base/file_util.h"
|
| #include "base/path_service.h"
|
| #include "base/process/process_handle.h"
|
| +#include "base/strings/string_util.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "build/build_config.h"
|
| #include "tools/gn/build_settings.h"
|
| @@ -179,30 +180,87 @@ void NinjaBuildWriter::WritePhonyAndAllRules() {
|
|
|
| // 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.
|
| + // isn't unique, also skip it. The exception is for the toplevel targets
|
| + // which we also find.
|
| std::map<std::string, int> small_name_count;
|
| - for (size_t i = 0; i < default_toolchain_targets_.size(); i++)
|
| - small_name_count[default_toolchain_targets_[i]->label().name()]++;
|
| -
|
| + std::vector<const Target*> toplevel_targets;
|
| for (size_t i = 0; i < default_toolchain_targets_.size(); i++) {
|
| const Target* target = default_toolchain_targets_[i];
|
| + const Label& label = target->label();
|
| + small_name_count[label.name()]++;
|
| +
|
| + // Look for targets with a name of the form
|
| + // dir = "//foo/", name = "foo"
|
| + // i.e. where the target name matches the top level directory. We will
|
| + // always write phony rules for these even if there is another target with
|
| + // the same short name.
|
| + const std::string& dir_string = label.dir().value();
|
| + if (dir_string.size() == label.name().size() + 3 && // Size matches.
|
| + dir_string[0] == '/' && dir_string[1] == '/' && // "//" at beginning.
|
| + dir_string[dir_string.size() - 1] == '/' && // "/" at end.
|
| + dir_string.compare(2, label.name().size(), label.name()) == 0)
|
| + toplevel_targets.push_back(target);
|
| + }
|
|
|
| + for (size_t i = 0; i < default_toolchain_targets_.size(); i++) {
|
| + const Target* target = default_toolchain_targets_[i];
|
| + const Label& label = target->label();
|
| OutputFile target_file = helper_.GetTargetOutputFile(target);
|
| - if (target_file.value() != target->label().name() &&
|
| - small_name_count[default_toolchain_targets_[i]->label().name()] == 1) {
|
| - out_ << "build " << target->label().name() << ": phony ";
|
| - path_output_.WriteFile(out_, target_file);
|
| - out_ << std::endl;
|
| +
|
| + // 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);
|
| +
|
| + // Write the directory name with no target name if they match
|
| + // (e.g. "//foo/bar:bar" -> "foo/bar").
|
| + if (FindLastDirComponent(label.dir()) == label.name()) {
|
| + std::string medium_name = DirectoryWithNoLastSlash(label.dir());
|
| + base::TrimString(medium_name, "/", &medium_name);
|
| + // 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);
|
| }
|
|
|
| + // Write short names for ones which are unique.
|
| + if (small_name_count[label.name()] == 1)
|
| + WritePhonyRule(target, target_file, label.name());
|
| +
|
| if (!all_rules.empty())
|
| all_rules.append(" $\n ");
|
| all_rules.append(target_file.value());
|
| }
|
|
|
| + // Pick up phony rules for the toplevel targets with non-unique names (which
|
| + // would have been skipped in the above loop).
|
| + for (size_t i = 0; i < toplevel_targets.size(); i++) {
|
| + if (small_name_count[toplevel_targets[i]->label().name()] > 1) {
|
| + const Target* target = toplevel_targets[i];
|
| + WritePhonyRule(target, helper_.GetTargetOutputFile(target),
|
| + target->label().name());
|
| + }
|
| + }
|
| +
|
| if (!all_rules.empty()) {
|
| out_ << "\nbuild all: phony " << all_rules << std::endl;
|
| out_ << "default all" << std::endl;
|
| }
|
| }
|
|
|
| +void NinjaBuildWriter::WritePhonyRule(const Target* target,
|
| + const OutputFile& target_file,
|
| + const std::string& phony_name) {
|
| + if (target_file.value() == phony_name)
|
| + return; // No need for a phony rule.
|
| +
|
| + EscapeOptions ninja_escape;
|
| + ninja_escape.mode = ESCAPE_NINJA;
|
| +
|
| + // Escape for special chars Ninja will handle.
|
| + std::string escaped = EscapeString(phony_name, ninja_escape, NULL);
|
| +
|
| + out_ << "build " << escaped << ": phony ";
|
| + path_output_.WriteFile(out_, target_file);
|
| + out_ << std::endl;
|
| +}
|
|
|