Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / tools / gn / ninja_action_target_writer.cc
blobfef58ac24fb6cf94fb7a3ac272f2d81addab6585
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_action_target_writer.h"
7 #include "base/strings/string_util.h"
8 #include "tools/gn/err.h"
9 #include "tools/gn/file_template.h"
10 #include "tools/gn/string_utils.h"
11 #include "tools/gn/target.h"
13 NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target,
14 const Toolchain* toolchain,
15 std::ostream& out)
16 : NinjaTargetWriter(target, toolchain, out),
17 path_output_no_escaping_(
18 target->settings()->build_settings()->build_dir(),
19 ESCAPE_NONE, false) {
22 NinjaActionTargetWriter::~NinjaActionTargetWriter() {
25 void NinjaActionTargetWriter::Run() {
26 FileTemplate args_template(target_->action_values().args());
27 std::string custom_rule_name = WriteRuleDefinition(args_template);
28 std::string implicit_deps = GetSourcesImplicitDeps();
30 // Collects all output files for writing below.
31 std::vector<OutputFile> output_files;
33 if (target_->output_type() == Target::ACTION_FOREACH) {
34 // Write separate build lines for each input source file.
35 WriteSourceRules(custom_rule_name, implicit_deps, args_template,
36 &output_files);
37 } else {
38 DCHECK(target_->output_type() == Target::ACTION);
40 // Write a rule that invokes the script once with the outputs as outputs,
41 // and the data as inputs.
42 out_ << "build";
43 if (target_->action_values().has_depfile()) {
44 out_ << " ";
45 WriteDepfile(SourceFile());
47 const Target::FileList& outputs = target_->action_values().outputs();
48 for (size_t i = 0; i < outputs.size(); i++) {
49 OutputFile output_path(
50 RemovePrefix(outputs[i].value(),
51 settings_->build_settings()->build_dir().value()));
52 output_files.push_back(output_path);
53 out_ << " ";
54 path_output_.WriteFile(out_, output_path);
57 out_ << ": " << custom_rule_name << implicit_deps;
59 // In the case of running the script once, we allow you to write the input
60 // dependencies in both sources and source_prereqs. source_prereqs are
61 // already in the implicit deps written above, but the sources aren't
62 // (since treating the sources this was is unique to an action).
63 const Target::FileList& sources = target_->sources();
64 for (size_t i = 0; i < sources.size(); i++) {
65 out_ << " ";
66 path_output_.WriteFile(out_, sources[i]);
68 out_ << std::endl;
70 if (target_->action_values().has_depfile()) {
71 out_ << " depfile = ";
72 WriteDepfile(SourceFile());
73 out_ << std::endl;
76 out_ << std::endl;
78 WriteStamp(output_files);
81 std::string NinjaActionTargetWriter::WriteRuleDefinition(
82 const FileTemplate& args_template) {
83 // Make a unique name for this rule.
85 // Use a unique name for the response file when there are multiple build
86 // steps so that they don't stomp on each other. When there are no sources,
87 // there will be only one invocation so we can use a simple name.
88 std::string target_label = target_->label().GetUserVisibleName(true);
89 std::string custom_rule_name(target_label);
90 base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
91 custom_rule_name.append("_rule");
93 if (settings_->IsWin()) {
94 // Send through gyp-win-tool and use a response file.
95 std::string rspfile = custom_rule_name;
96 if (has_sources())
97 rspfile += ".$unique_name";
98 rspfile += ".rsp";
100 out_ << "rule " << custom_rule_name << std::endl;
101 out_ << " command = ";
102 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
103 // TODO(brettw) this hardcodes "environment.x86" which is something that
104 // the Chrome Windows toolchain writes. We should have a way to invoke
105 // python without requiring this gyp_win_tool thing.
106 out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile
107 << std::endl;
108 out_ << " description = ACTION " << target_label << std::endl;
109 out_ << " restat = 1" << std::endl;
110 out_ << " rspfile = " << rspfile << std::endl;
112 // The build command goes in the rsp file.
113 out_ << " rspfile_content = ";
114 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
115 out_ << " ";
116 path_output_.WriteFile(out_, target_->action_values().script());
117 args_template.WriteWithNinjaExpansions(out_);
118 out_ << std::endl;
119 } else {
120 // Posix can execute Python directly.
121 out_ << "rule " << custom_rule_name << std::endl;
122 out_ << " command = ";
123 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
124 out_ << " ";
125 path_output_.WriteFile(out_, target_->action_values().script());
126 args_template.WriteWithNinjaExpansions(out_);
127 out_ << std::endl;
128 out_ << " description = ACTION " << target_label << std::endl;
129 out_ << " restat = 1" << std::endl;
132 out_ << std::endl;
133 return custom_rule_name;
136 void NinjaActionTargetWriter::WriteArgsSubstitutions(
137 const SourceFile& source,
138 const FileTemplate& args_template) {
139 std::ostringstream source_file_stream;
140 path_output_no_escaping_.WriteFile(source_file_stream, source);
142 EscapeOptions template_escape_options;
143 template_escape_options.mode = ESCAPE_NINJA_SHELL;
144 template_escape_options.inhibit_quoting = true;
146 args_template.WriteNinjaVariablesForSubstitution(
147 out_, source_file_stream.str(), template_escape_options);
150 void NinjaActionTargetWriter::WriteSourceRules(
151 const std::string& custom_rule_name,
152 const std::string& implicit_deps,
153 const FileTemplate& args_template,
154 std::vector<OutputFile>* output_files) {
155 FileTemplate output_template(GetOutputTemplate());
157 const Target::FileList& sources = target_->sources();
158 for (size_t i = 0; i < sources.size(); i++) {
159 out_ << "build";
160 WriteOutputFilesForBuildLine(output_template, sources[i], output_files);
162 out_ << ": " << custom_rule_name << " ";
163 path_output_.WriteFile(out_, sources[i]);
164 out_ << implicit_deps << std::endl;
166 // Windows needs a unique ID for the response file.
167 if (target_->settings()->IsWin())
168 out_ << " unique_name = " << i << std::endl;
170 if (args_template.has_substitutions())
171 WriteArgsSubstitutions(sources[i], args_template);
173 if (target_->action_values().has_depfile()) {
174 out_ << " depfile = ";
175 WriteDepfile(sources[i]);
176 out_ << std::endl;
181 void NinjaActionTargetWriter::WriteStamp(
182 const std::vector<OutputFile>& output_files) {
183 out_ << "build ";
184 path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
185 out_ << ": "
186 << helper_.GetRulePrefix(target_->settings())
187 << "stamp";
188 for (size_t i = 0; i < output_files.size(); i++) {
189 out_ << " ";
190 path_output_.WriteFile(out_, output_files[i]);
192 out_ << std::endl;
195 void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
196 const FileTemplate& output_template,
197 const SourceFile& source,
198 std::vector<OutputFile>* output_files) {
199 // If there is a depfile specified we need to list it as the first output as
200 // that is what ninja will expect the depfile to refer to itself as.
201 if (target_->action_values().has_depfile()) {
202 out_ << " ";
203 WriteDepfile(source);
205 std::vector<std::string> output_template_result;
206 output_template.ApplyString(source.value(), &output_template_result);
207 for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) {
208 OutputFile output_path(output_template_result[out_i]);
209 output_files->push_back(output_path);
210 out_ << " ";
211 path_output_.WriteFile(out_, output_path);
215 void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
216 std::vector<std::string> result;
217 GetDepfileTemplate().ApplyString(source.value(), &result);
218 path_output_.WriteFile(out_, OutputFile(result[0]));
221 FileTemplate NinjaActionTargetWriter::GetDepfileTemplate() const {
222 std::vector<std::string> template_args;
223 std::string depfile_relative_to_build_dir =
224 RemovePrefix(target_->action_values().depfile().value(),
225 settings_->build_settings()->build_dir().value());
226 template_args.push_back(depfile_relative_to_build_dir);
227 return FileTemplate(template_args);