Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / tools / gn / ninja_build_writer.cc
blob11b36e6b591e74a85753f2998aad2dcfe003dc36
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
3 // found in the LICENSE file.
5 #include "tools/gn/ninja_build_writer.h"
7 #include <fstream>
8 #include <map>
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/path_service.h"
13 #include "base/process/process_handle.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "build/build_config.h"
16 #include "tools/gn/build_settings.h"
17 #include "tools/gn/escape.h"
18 #include "tools/gn/filesystem_utils.h"
19 #include "tools/gn/input_file_manager.h"
20 #include "tools/gn/scheduler.h"
21 #include "tools/gn/target.h"
22 #include "tools/gn/trace.h"
24 #if defined(OS_WIN)
25 #include <windows.h>
26 #endif
28 namespace {
30 std::string GetSelfInvocationCommand(const BuildSettings* build_settings) {
31 base::FilePath executable;
32 PathService::Get(base::FILE_EXE, &executable);
34 CommandLine cmdline(executable.NormalizePathSeparatorsTo('/'));
35 cmdline.AppendArg("gen");
36 cmdline.AppendArg(build_settings->build_dir().value());
37 cmdline.AppendSwitchPath("--root", build_settings->root_path());
38 cmdline.AppendSwitch("-q"); // Don't write output.
40 EscapeOptions escape_shell;
41 escape_shell.mode = ESCAPE_SHELL;
42 #if defined(OS_WIN)
43 // The command line code quoting varies by platform. We have one string,
44 // possibly with spaces, that we want to quote. The Windows command line
45 // quotes again, so we don't want quoting. The Posix one doesn't.
46 escape_shell.inhibit_quoting = true;
47 #endif
49 const CommandLine& our_cmdline = *CommandLine::ForCurrentProcess();
50 const CommandLine::SwitchMap& switches = our_cmdline.GetSwitches();
51 for (CommandLine::SwitchMap::const_iterator i = switches.begin();
52 i != switches.end(); ++i) {
53 if (i->first != "q" && i->first != "root") {
54 std::string escaped_value =
55 EscapeString(FilePathToUTF8(i->second), escape_shell, NULL);
56 cmdline.AppendSwitchASCII(i->first, escaped_value);
60 #if defined(OS_WIN)
61 return base::WideToUTF8(cmdline.GetCommandLineString());
62 #else
63 return cmdline.GetCommandLineString();
64 #endif
67 } // namespace
69 NinjaBuildWriter::NinjaBuildWriter(
70 const BuildSettings* build_settings,
71 const std::vector<const Settings*>& all_settings,
72 const std::vector<const Target*>& default_toolchain_targets,
73 std::ostream& out,
74 std::ostream& dep_out)
75 : build_settings_(build_settings),
76 all_settings_(all_settings),
77 default_toolchain_targets_(default_toolchain_targets),
78 out_(out),
79 dep_out_(dep_out),
80 path_output_(build_settings->build_dir(), ESCAPE_NINJA, false),
81 helper_(build_settings) {
84 NinjaBuildWriter::~NinjaBuildWriter() {
87 void NinjaBuildWriter::Run() {
88 WriteNinjaRules();
89 WriteSubninjas();
90 WritePhonyAndAllRules();
93 // static
94 bool NinjaBuildWriter::RunAndWriteFile(
95 const BuildSettings* build_settings,
96 const std::vector<const Settings*>& all_settings,
97 const std::vector<const Target*>& default_toolchain_targets) {
98 ScopedTrace trace(TraceItem::TRACE_FILE_WRITE, "build.ninja");
100 base::FilePath ninja_file(build_settings->GetFullPath(
101 SourceFile(build_settings->build_dir().value() + "build.ninja")));
102 base::CreateDirectory(ninja_file.DirName());
104 std::ofstream file;
105 file.open(FilePathToUTF8(ninja_file).c_str(),
106 std::ios_base::out | std::ios_base::binary);
107 if (file.fail())
108 return false;
110 std::ofstream depfile;
111 depfile.open((FilePathToUTF8(ninja_file) + ".d").c_str(),
112 std::ios_base::out | std::ios_base::binary);
113 if (depfile.fail())
114 return false;
116 NinjaBuildWriter gen(build_settings, all_settings,
117 default_toolchain_targets, file, depfile);
118 gen.Run();
119 return true;
122 void NinjaBuildWriter::WriteNinjaRules() {
123 out_ << "rule gn\n";
124 out_ << " command = " << GetSelfInvocationCommand(build_settings_) << "\n";
125 out_ << " description = Regenerating ninja files\n\n";
127 // This rule will regenerate the ninja files when any input file has changed.
128 out_ << "build build.ninja: gn\n"
129 << " generator = 1\n"
130 << " depfile = build.ninja.d\n";
132 // Provide a way to force regenerating ninja files if the user is suspicious
133 // something is out-of-date. This will be "ninja refresh".
134 out_ << "\nbuild refresh: gn\n";
136 // Provide a way to see what flags are associated with this build:
137 // This will be "ninja show".
138 const CommandLine& our_cmdline = *CommandLine::ForCurrentProcess();
139 std::string args = our_cmdline.GetSwitchValueASCII("args");
140 out_ << "rule echo\n";
141 out_ << " command = echo $text\n";
142 out_ << " description = ECHO $desc\n";
143 out_ << "build show: echo\n";
144 out_ << " desc = build arguments:\n";
145 out_ << " text = "
146 << (args.empty() ? std::string("No build args, using defaults.") : args)
147 << "\n";
149 // Input build files. These go in the ".d" file. If we write them as
150 // dependencies in the .ninja file itself, ninja will expect the files to
151 // exist and will error if they don't. When files are listed in a depfile,
152 // missing files are ignored.
153 dep_out_ << "build.ninja:";
154 std::vector<base::FilePath> input_files;
155 g_scheduler->input_file_manager()->GetAllPhysicalInputFileNames(&input_files);
156 for (size_t i = 0; i < input_files.size(); i++)
157 dep_out_ << " " << FilePathToUTF8(input_files[i]);
159 // Other files read by the build.
160 std::vector<base::FilePath> other_files = g_scheduler->GetGenDependencies();
161 for (size_t i = 0; i < other_files.size(); i++)
162 dep_out_ << " " << FilePathToUTF8(other_files[i]);
164 out_ << std::endl;
167 void NinjaBuildWriter::WriteSubninjas() {
168 for (size_t i = 0; i < all_settings_.size(); i++) {
169 out_ << "subninja ";
170 path_output_.WriteFile(out_,
171 helper_.GetNinjaFileForToolchain(all_settings_[i]));
172 out_ << std::endl;
174 out_ << std::endl;
177 void NinjaBuildWriter::WritePhonyAndAllRules() {
178 std::string all_rules;
180 // Write phony rules for all uniquely-named targets in the default toolchain.
181 // Don't do other toolchains or we'll get naming conflicts, and if the name
182 // isn't unique, also skip it.
183 std::map<std::string, int> small_name_count;
184 for (size_t i = 0; i < default_toolchain_targets_.size(); i++)
185 small_name_count[default_toolchain_targets_[i]->label().name()]++;
187 for (size_t i = 0; i < default_toolchain_targets_.size(); i++) {
188 const Target* target = default_toolchain_targets_[i];
190 OutputFile target_file = helper_.GetTargetOutputFile(target);
191 if (target_file.value() != target->label().name() &&
192 small_name_count[default_toolchain_targets_[i]->label().name()] == 1) {
193 out_ << "build " << target->label().name() << ": phony ";
194 path_output_.WriteFile(out_, target_file);
195 out_ << std::endl;
198 if (!all_rules.empty())
199 all_rules.append(" $\n ");
200 all_rules.append(target_file.value());
203 if (!all_rules.empty()) {
204 out_ << "\nbuild all: phony " << all_rules << std::endl;
205 out_ << "default all" << std::endl;