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
,
16 : NinjaTargetWriter(target
, toolchain
, out
),
17 path_output_no_escaping_(
18 target
->settings()->build_settings()->build_dir(),
22 NinjaActionTargetWriter::~NinjaActionTargetWriter() {
25 void NinjaActionTargetWriter::Run() {
26 FileTemplate
args_template(target_
->settings(),
27 target_
->action_values().args());
28 std::string custom_rule_name
= WriteRuleDefinition(args_template
);
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
35 std::vector
<const Target
*> extra_hard_deps
;
36 for (size_t i
= 0; i
< target_
->deps().size(); i
++)
37 extra_hard_deps
.push_back(target_
->deps()[i
].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 std::string implicit_deps
= WriteInputDepsStampAndGetDep(extra_hard_deps
);
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
, implicit_deps
, args_template
,
56 DCHECK(target_
->output_type() == Target::ACTION
);
58 // Write a rule that invokes the script once with the outputs as outputs,
59 // and the data as inputs.
61 const Target::FileList
& outputs
= target_
->action_values().outputs();
62 for (size_t i
= 0; i
< outputs
.size(); i
++) {
63 OutputFile
output_path(
64 RemovePrefix(outputs
[i
].value(),
65 settings_
->build_settings()->build_dir().value()));
66 output_files
.push_back(output_path
);
68 path_output_
.WriteFile(out_
, output_path
);
71 out_
<< ": " << custom_rule_name
<< implicit_deps
<< std::endl
;
72 if (target_
->action_values().has_depfile()) {
73 out_
<< " depfile = ";
74 WriteDepfile(SourceFile());
80 WriteStamp(output_files
);
83 std::string
NinjaActionTargetWriter::WriteRuleDefinition(
84 const FileTemplate
& args_template
) {
85 // Make a unique name for this rule.
87 // Use a unique name for the response file when there are multiple build
88 // steps so that they don't stomp on each other. When there are no sources,
89 // there will be only one invocation so we can use a simple name.
90 std::string target_label
= target_
->label().GetUserVisibleName(true);
91 std::string
custom_rule_name(target_label
);
92 base::ReplaceChars(custom_rule_name
, ":/()", "_", &custom_rule_name
);
93 custom_rule_name
.append("_rule");
95 if (settings_
->IsWin()) {
96 // Send through gyp-win-tool and use a response file.
97 std::string rspfile
= custom_rule_name
;
99 rspfile
+= ".$unique_name";
102 out_
<< "rule " << custom_rule_name
<< std::endl
;
103 out_
<< " command = ";
104 path_output_
.WriteFile(out_
, settings_
->build_settings()->python_path());
105 // TODO(brettw) this hardcodes "environment.x86" which is something that
106 // the Chrome Windows toolchain writes. We should have a way to invoke
107 // python without requiring this gyp_win_tool thing.
108 out_
<< " gyp-win-tool action-wrapper environment.x86 " << rspfile
110 out_
<< " description = ACTION " << target_label
<< std::endl
;
111 out_
<< " restat = 1" << std::endl
;
112 out_
<< " rspfile = " << rspfile
<< std::endl
;
114 // The build command goes in the rsp file.
115 out_
<< " rspfile_content = ";
116 path_output_
.WriteFile(out_
, settings_
->build_settings()->python_path());
118 path_output_
.WriteFile(out_
, target_
->action_values().script());
119 args_template
.WriteWithNinjaExpansions(out_
);
122 // Posix can execute Python directly.
123 out_
<< "rule " << custom_rule_name
<< std::endl
;
124 out_
<< " command = ";
125 path_output_
.WriteFile(out_
, settings_
->build_settings()->python_path());
127 path_output_
.WriteFile(out_
, target_
->action_values().script());
128 args_template
.WriteWithNinjaExpansions(out_
);
130 out_
<< " description = ACTION " << target_label
<< std::endl
;
131 out_
<< " restat = 1" << std::endl
;
134 return custom_rule_name
;
137 void NinjaActionTargetWriter::WriteArgsSubstitutions(
138 const SourceFile
& source
,
139 const FileTemplate
& args_template
) {
140 EscapeOptions template_escape_options
;
141 template_escape_options
.mode
= ESCAPE_NINJA_COMMAND
;
143 args_template
.WriteNinjaVariablesForSubstitution(
144 out_
, target_
->settings(), source
, template_escape_options
);
147 void NinjaActionTargetWriter::WriteSourceRules(
148 const std::string
& custom_rule_name
,
149 const std::string
& implicit_deps
,
150 const FileTemplate
& args_template
,
151 std::vector
<OutputFile
>* output_files
) {
152 FileTemplate
output_template(GetOutputTemplate());
154 const Target::FileList
& sources
= target_
->sources();
155 for (size_t i
= 0; i
< sources
.size(); i
++) {
157 WriteOutputFilesForBuildLine(output_template
, sources
[i
], output_files
);
159 out_
<< ": " << custom_rule_name
<< " ";
160 path_output_
.WriteFile(out_
, sources
[i
]);
161 out_
<< implicit_deps
<< std::endl
;
163 // Windows needs a unique ID for the response file.
164 if (target_
->settings()->IsWin())
165 out_
<< " unique_name = " << i
<< std::endl
;
167 if (args_template
.has_substitutions())
168 WriteArgsSubstitutions(sources
[i
], args_template
);
170 if (target_
->action_values().has_depfile()) {
171 out_
<< " depfile = ";
172 WriteDepfile(sources
[i
]);
178 void NinjaActionTargetWriter::WriteStamp(
179 const std::vector
<OutputFile
>& output_files
) {
181 path_output_
.WriteFile(out_
, helper_
.GetTargetOutputFile(target_
));
183 << helper_
.GetRulePrefix(target_
->settings())
186 // The action stamp depends on all output files from running the action.
187 for (size_t i
= 0; i
< output_files
.size(); i
++) {
189 path_output_
.WriteFile(out_
, output_files
[i
]);
192 // It also depends on all datadeps. These are needed at runtime and should
193 // be compiled when the action is, but don't need to be done before we run
195 for (size_t i
= 0; i
< target_
->datadeps().size(); i
++) {
197 path_output_
.WriteFile(out_
,
198 helper_
.GetTargetOutputFile(target_
->datadeps()[i
].ptr
));
204 void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
205 const FileTemplate
& output_template
,
206 const SourceFile
& source
,
207 std::vector
<OutputFile
>* output_files
) {
208 std::vector
<std::string
> output_template_result
;
209 output_template
.Apply(source
, &output_template_result
);
210 for (size_t out_i
= 0; out_i
< output_template_result
.size(); out_i
++) {
211 OutputFile
output_path(output_template_result
[out_i
]);
212 output_files
->push_back(output_path
);
214 path_output_
.WriteFile(out_
, output_path
);
218 void NinjaActionTargetWriter::WriteDepfile(const SourceFile
& source
) {
219 std::vector
<std::string
> result
;
220 GetDepfileTemplate().Apply(source
, &result
);
221 path_output_
.WriteFile(out_
, OutputFile(result
[0]));
224 FileTemplate
NinjaActionTargetWriter::GetDepfileTemplate() const {
225 std::vector
<std::string
> template_args
;
226 std::string depfile_relative_to_build_dir
=
227 RemovePrefix(target_
->action_values().depfile().value(),
228 settings_
->build_settings()->build_dir().value());
229 template_args
.push_back(depfile_relative_to_build_dir
);
230 return FileTemplate(settings_
, template_args
);