1d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// found in the LICENSE file.
4d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/ninja_build_writer.h"
6d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
7d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include <fstream>
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <map>
9d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
10d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/command_line.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/path_service.h"
13d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/process/process_handle.h"
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/strings/string_util.h"
15d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/utf_string_conversions.h"
16d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "build/build_config.h"
17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/build_settings.h"
183240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch#include "tools/gn/escape.h"
19d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/filesystem_utils.h"
20d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/input_file_manager.h"
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "tools/gn/ninja_utils.h"
22d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/scheduler.h"
23d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/target.h"
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "tools/gn/trace.h"
25d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
26d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
27d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include <windows.h>
28d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
29d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
30d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochnamespace {
31d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
32d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstd::string GetSelfInvocationCommand(const BuildSettings* build_settings) {
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath executable;
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  PathService::Get(base::FILE_EXE, &executable);
35d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
36c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  CommandLine cmdline(executable.NormalizePathSeparatorsTo('/'));
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  cmdline.AppendArg("gen");
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  cmdline.AppendArg(build_settings->build_dir().value());
39d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  cmdline.AppendSwitchPath("--root", build_settings->root_path());
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  cmdline.AppendSwitch("-q");  // Don't write output.
41d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  EscapeOptions escape_shell;
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  escape_shell.mode = ESCAPE_NINJA_COMMAND;
441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#if defined(OS_WIN)
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The command line code quoting varies by platform. We have one string,
461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // possibly with spaces, that we want to quote. The Windows command line
471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // quotes again, so we don't want quoting. The Posix one doesn't.
481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  escape_shell.inhibit_quoting = true;
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const CommandLine& our_cmdline = *CommandLine::ForCurrentProcess();
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const CommandLine::SwitchMap& switches = our_cmdline.GetSwitches();
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (CommandLine::SwitchMap::const_iterator i = switches.begin();
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)       i != switches.end(); ++i) {
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Only write arguments we haven't already written. Always skip "args"
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // since those will have been written to the file and will be used
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // implicitly in the future. Keeping --args would mean changes to the file
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // would be ignored.
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (i->first != "q" && i->first != "root" && i->first != "args") {
608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      std::string escaped_value =
618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          EscapeString(FilePathToUTF8(i->second), escape_shell, NULL);
628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      cmdline.AppendSwitchASCII(i->first, escaped_value);
638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    }
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
65d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
66d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::WideToUTF8(cmdline.GetCommandLineString());
68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#else
69d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return cmdline.GetCommandLineString();
70d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
71d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
72d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
73d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}  // namespace
74d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
75d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochNinjaBuildWriter::NinjaBuildWriter(
76d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const BuildSettings* build_settings,
77d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::vector<const Settings*>& all_settings,
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const Toolchain* default_toolchain,
79d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::vector<const Target*>& default_toolchain_targets,
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::ostream& out,
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::ostream& dep_out)
82d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    : build_settings_(build_settings),
83d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      all_settings_(all_settings),
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      default_toolchain_(default_toolchain),
85d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      default_toolchain_targets_(default_toolchain_targets),
86d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      out_(out),
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      dep_out_(dep_out),
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      path_output_(build_settings->build_dir(), ESCAPE_NINJA) {
89d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
90d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
91d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochNinjaBuildWriter::~NinjaBuildWriter() {
92d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
93d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
94d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaBuildWriter::Run() {
95d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  WriteNinjaRules();
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  WriteLinkPool();
97d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  WriteSubninjas();
98d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  WritePhonyAndAllRules();
99d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
100d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
101d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// static
102d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool NinjaBuildWriter::RunAndWriteFile(
103d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const BuildSettings* build_settings,
104d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::vector<const Settings*>& all_settings,
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const Toolchain* default_toolchain,
106d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const std::vector<const Target*>& default_toolchain_targets) {
10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja");
10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
109d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  base::FilePath ninja_file(build_settings->GetFullPath(
110d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      SourceFile(build_settings->build_dir().value() + "build.ninja")));
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::CreateDirectory(ninja_file.DirName());
112d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
113d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::ofstream file;
114d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  file.open(FilePathToUTF8(ninja_file).c_str(),
115d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            std::ios_base::out | std::ios_base::binary);
116d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (file.fail())
117d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return false;
118d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::ofstream depfile;
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  depfile.open((FilePathToUTF8(ninja_file) + ".d").c_str(),
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)               std::ios_base::out | std::ios_base::binary);
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (depfile.fail())
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  NinjaBuildWriter gen(build_settings, all_settings, default_toolchain,
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                       default_toolchain_targets, file, depfile);
127d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  gen.Run();
128d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return true;
129d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
130d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
131d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaBuildWriter::WriteNinjaRules() {
132d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "rule gn\n";
133d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << "  command = " << GetSelfInvocationCommand(build_settings_) << "\n";
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  out_ << "  description = Regenerating ninja files\n\n";
135d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // This rule will regenerate the ninja files when any input file has changed.
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  out_ << "build build.ninja: gn\n"
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       << "  generator = 1\n"
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       << "  depfile = build.ninja.d\n";
140d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Input build files. These go in the ".d" file. If we write them as
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // dependencies in the .ninja file itself, ninja will expect the files to
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // exist and will error if they don't. When files are listed in a depfile,
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // missing files are ignored.
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  dep_out_ << "build.ninja:";
1463240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  std::vector<base::FilePath> input_files;
1473240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  g_scheduler->input_file_manager()->GetAllPhysicalInputFileNames(&input_files);
1483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  for (size_t i = 0; i < input_files.size(); i++)
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    dep_out_ << " " << FilePathToUTF8(input_files[i]);
150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Other files read by the build.
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<base::FilePath> other_files = g_scheduler->GetGenDependencies();
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (size_t i = 0; i < other_files.size(); i++)
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    dep_out_ << " " << FilePathToUTF8(other_files[i]);
155d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  out_ << std::endl;
157d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
158d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid NinjaBuildWriter::WriteLinkPool() {
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  out_ << "pool link_pool\n"
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       << "  depth = " << default_toolchain_->concurrent_links() << std::endl
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       << std::endl;
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
165d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaBuildWriter::WriteSubninjas() {
166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < all_settings_.size(); i++) {
167d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "subninja ";
16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    path_output_.WriteFile(out_, GetNinjaFileForToolchain(all_settings_[i]));
169d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << std::endl;
170d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
171d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  out_ << std::endl;
172d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
174d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NinjaBuildWriter::WritePhonyAndAllRules() {
175d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string all_rules;
176d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Write phony rules for all uniquely-named targets in the default toolchain.
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Don't do other toolchains or we'll get naming conflicts, and if the name
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // isn't unique, also skip it. The exception is for the toplevel targets
1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // which we also find.
181c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::map<std::string, int> small_name_count;
1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<const Target*> toplevel_targets;
183d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < default_toolchain_targets_.size(); i++) {
184d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const Target* target = default_toolchain_targets_[i];
1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const Label& label = target->label();
1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    small_name_count[label.name()]++;
1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Look for targets with a name of the form
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    //   dir = "//foo/", name = "foo"
1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // i.e. where the target name matches the top level directory. We will
1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // always write phony rules for these even if there is another target with
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // the same short name.
1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& dir_string = label.dir().value();
1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (dir_string.size() == label.name().size() + 3 &&  // Size matches.
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        dir_string[0] == '/' && dir_string[1] == '/' &&  // "//" at beginning.
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        dir_string[dir_string.size() - 1] == '/' &&  // "/" at end.
1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        dir_string.compare(2, label.name().size(), label.name()) == 0)
1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      toplevel_targets.push_back(target);
1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
200d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < default_toolchain_targets_.size(); i++) {
2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const Target* target = default_toolchain_targets_[i];
2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const Label& label = target->label();
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    OutputFile target_file(target->dependency_output_file());
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // The output files may have leading "./" so normalize those away.
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NormalizePath(&target_file.value());
2075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Write the long name "foo/bar:baz" for the target "//foo/bar:baz".
2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    std::string long_name = label.GetUserVisibleName(false);
2105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    base::TrimString(long_name, "/", &long_name);
2115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    WritePhonyRule(target, target_file, long_name);
2125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Write the directory name with no target name if they match
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // (e.g. "//foo/bar:bar" -> "foo/bar").
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (FindLastDirComponent(label.dir()) == label.name()) {
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      std::string medium_name =  DirectoryWithNoLastSlash(label.dir());
2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      base::TrimString(medium_name, "/", &medium_name);
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      // That may have generated a name the same as the short name of the
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      // target which we already wrote.
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (medium_name != label.name())
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        WritePhonyRule(target, target_file, medium_name);
222d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
223d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Write short names for ones which are unique.
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (small_name_count[label.name()] == 1)
2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      WritePhonyRule(target, target_file, label.name());
2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
228d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (!all_rules.empty())
229d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      all_rules.append(" $\n    ");
230d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    all_rules.append(target_file.value());
231d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
232d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Pick up phony rules for the toplevel targets with non-unique names (which
2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // would have been skipped in the above loop).
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (size_t i = 0; i < toplevel_targets.size(); i++) {
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (small_name_count[toplevel_targets[i]->label().name()] > 1) {
2375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const Target* target = toplevel_targets[i];
23803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      WritePhonyRule(target, target->dependency_output_file(),
2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                     target->label().name());
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
243d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!all_rules.empty()) {
244d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "\nbuild all: phony " << all_rules << std::endl;
245d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    out_ << "default all" << std::endl;
246d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
247d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
248d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid NinjaBuildWriter::WritePhonyRule(const Target* target,
2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                      const OutputFile& target_file,
2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                      const std::string& phony_name) {
2525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (target_file.value() == phony_name)
2535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;  // No need for a phony rule.
2545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EscapeOptions ninja_escape;
2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ninja_escape.mode = ESCAPE_NINJA;
2575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Escape for special chars Ninja will handle.
2595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::string escaped = EscapeString(phony_name, ninja_escape, NULL);
2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  out_ << "build " << escaped << ": phony ";
2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  path_output_.WriteFile(out_, target_file);
2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  out_ << std::endl;
2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
265