Add ICU message format support
[chromium-blink-merge.git] / tools / gn / ninja_action_target_writer.cc
blob84ec0723c6e3821da4af29ad0da7f459174edcaf
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/deps_iterator.h"
9 #include "tools/gn/err.h"
10 #include "tools/gn/settings.h"
11 #include "tools/gn/string_utils.h"
12 #include "tools/gn/substitution_writer.h"
13 #include "tools/gn/target.h"
15 NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target,
16 std::ostream& out)
17 : NinjaTargetWriter(target, out),
18 path_output_no_escaping_(
19 target->settings()->build_settings()->build_dir(),
20 target->settings()->build_settings()->root_path_utf8(),
21 ESCAPE_NONE) {
24 NinjaActionTargetWriter::~NinjaActionTargetWriter() {
27 void NinjaActionTargetWriter::Run() {
28 std::string custom_rule_name = WriteRuleDefinition();
30 // Collect our deps to pass as "extra hard dependencies" for input deps. This
31 // will force all of the action's dependencies to be completed before the
32 // action is run. Usually, if an action has a dependency, it will be
33 // operating on the result of that previous step, so we need to be sure to
34 // serialize these.
35 std::vector<const Target*> extra_hard_deps;
36 for (const auto& pair : target_->GetDeps(Target::DEPS_LINKED))
37 extra_hard_deps.push_back(pair.ptr);
39 // For ACTIONs this is a bit inefficient since it creates an input dep
40 // stamp file even though we're only going to use it once. It would save a
41 // build step to skip this and write the order-only deps directly on the
42 // build rule. This should probably be handled by WriteInputDepsStampAndGetDep
43 // automatically if we supply a count of sources (so it can optimize based on
44 // how many times things would be duplicated).
45 OutputFile input_dep = WriteInputDepsStampAndGetDep(extra_hard_deps);
46 out_ << std::endl;
48 // Collects all output files for writing below.
49 std::vector<OutputFile> output_files;
51 if (target_->output_type() == Target::ACTION_FOREACH) {
52 // Write separate build lines for each input source file.
53 WriteSourceRules(custom_rule_name, input_dep, &output_files);
54 } else {
55 DCHECK(target_->output_type() == Target::ACTION);
57 // Write a rule that invokes the script once with the outputs as outputs,
58 // and the data as inputs. It does not depend on the sources.
59 out_ << "build";
60 SubstitutionWriter::GetListAsOutputFiles(
61 settings_, target_->action_values().outputs(), &output_files);
62 path_output_.WriteFiles(out_, output_files);
64 out_ << ": " << custom_rule_name;
65 if (!input_dep.value().empty()) {
66 // As in WriteSourceRules, we want to force this target to rebuild any
67 // time any of its dependencies change.
68 out_ << " | ";
69 path_output_.WriteFile(out_, input_dep);
71 out_ << std::endl;
72 if (target_->action_values().has_depfile()) {
73 out_ << " depfile = ";
74 WriteDepfile(SourceFile());
75 out_ << std::endl;
78 out_ << std::endl;
80 // Write the stamp, which also depends on all data deps. These are needed at
81 // runtime and should be compiled when the action is, but don't need to be
82 // done before we run the action.
83 std::vector<OutputFile> data_outs;
84 for (const auto& dep : target_->data_deps())
85 data_outs.push_back(dep.ptr->dependency_output_file());
86 WriteStampForTarget(output_files, data_outs);
89 std::string NinjaActionTargetWriter::WriteRuleDefinition() {
90 // Make a unique name for this rule.
92 // Use a unique name for the response file when there are multiple build
93 // steps so that they don't stomp on each other. When there are no sources,
94 // there will be only one invocation so we can use a simple name.
95 std::string target_label = target_->label().GetUserVisibleName(true);
96 std::string custom_rule_name(target_label);
97 base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
98 custom_rule_name.append("_rule");
100 const SubstitutionList& args = target_->action_values().args();
101 EscapeOptions args_escape_options;
102 args_escape_options.mode = ESCAPE_NINJA_COMMAND;
104 if (settings_->IsWin()) {
105 // Send through gyp-win-tool and use a response file.
106 std::string rspfile = custom_rule_name;
107 if (!target_->sources().empty())
108 rspfile += ".$unique_name";
109 rspfile += ".rsp";
111 out_ << "rule " << custom_rule_name << std::endl;
112 out_ << " command = ";
113 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
114 // TODO(brettw) this hardcodes "environment.x86" which is something that
115 // the Chrome Windows toolchain writes. We should have a way to invoke
116 // python without requiring this gyp_win_tool thing.
117 out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile
118 << std::endl;
119 out_ << " description = ACTION " << target_label << std::endl;
120 out_ << " restat = 1" << std::endl;
121 out_ << " rspfile = " << rspfile << std::endl;
123 // The build command goes in the rsp file.
124 out_ << " rspfile_content = ";
125 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
126 out_ << " ";
127 path_output_.WriteFile(out_, target_->action_values().script());
128 for (const auto& arg : args.list()) {
129 out_ << " ";
130 SubstitutionWriter::WriteWithNinjaVariables(
131 arg, args_escape_options, out_);
133 out_ << std::endl;
134 } else {
135 // Posix can execute Python directly.
136 out_ << "rule " << custom_rule_name << std::endl;
137 out_ << " command = ";
138 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
139 out_ << " ";
140 path_output_.WriteFile(out_, target_->action_values().script());
141 for (const auto& arg : args.list()) {
142 out_ << " ";
143 SubstitutionWriter::WriteWithNinjaVariables(
144 arg, args_escape_options, out_);
146 out_ << std::endl;
147 out_ << " description = ACTION " << target_label << std::endl;
148 out_ << " restat = 1" << std::endl;
151 return custom_rule_name;
154 void NinjaActionTargetWriter::WriteSourceRules(
155 const std::string& custom_rule_name,
156 const OutputFile& input_dep,
157 std::vector<OutputFile>* output_files) {
158 EscapeOptions args_escape_options;
159 args_escape_options.mode = ESCAPE_NINJA_COMMAND;
160 // We're writing the substitution values, these should not be quoted since
161 // they will get pasted into the real command line.
162 args_escape_options.inhibit_quoting = true;
164 const std::vector<SubstitutionType>& args_substitutions_used =
165 target_->action_values().args().required_types();
167 const Target::FileList& sources = target_->sources();
168 for (size_t i = 0; i < sources.size(); i++) {
169 out_ << "build";
170 WriteOutputFilesForBuildLine(sources[i], output_files);
172 out_ << ": " << custom_rule_name << " ";
173 path_output_.WriteFile(out_, sources[i]);
174 if (!input_dep.value().empty()) {
175 // Using "|" for the dependencies forces all implicit dependencies to be
176 // fully up-to-date before running the action, and will re-run this
177 // action if any input dependencies change. This is important because
178 // this action may consume the outputs of previous steps.
179 out_ << " | ";
180 path_output_.WriteFile(out_, input_dep);
182 out_ << std::endl;
184 // Windows needs a unique ID for the response file.
185 if (target_->settings()->IsWin())
186 out_ << " unique_name = " << i << std::endl;
188 SubstitutionWriter::WriteNinjaVariablesForSource(
189 settings_, sources[i], args_substitutions_used,
190 args_escape_options, out_);
192 if (target_->action_values().has_depfile()) {
193 out_ << " depfile = ";
194 WriteDepfile(sources[i]);
195 out_ << std::endl;
200 void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
201 const SourceFile& source,
202 std::vector<OutputFile>* output_files) {
203 size_t first_output_index = output_files->size();
205 SubstitutionWriter::ApplyListToSourceAsOutputFile(
206 settings_, target_->action_values().outputs(), source, output_files);
208 for (size_t i = first_output_index; i < output_files->size(); i++) {
209 out_ << " ";
210 path_output_.WriteFile(out_, (*output_files)[i]);
214 void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
215 path_output_.WriteFile(out_,
216 SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
217 settings_, target_->action_values().depfile(), source));