Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / gn / ninja_action_target_writer.cc
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.
4
5 #include "tools/gn/ninja_action_target_writer.h"
6
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"
12
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) {
20 }
21
22 NinjaActionTargetWriter::~NinjaActionTargetWriter() {
23 }
24
25 void NinjaActionTargetWriter::Run() {
26   FileTemplate args_template(target_->action_values().args());
27   std::string custom_rule_name = WriteRuleDefinition(args_template);
28
29   // Collect our deps to pass as "extra hard dependencies" for input deps. This
30   // will force all of the action's dependencies to be completed before the
31   // action is run. Usually, if an action has a dependency, it will be
32   // operating on the result of that previous step, so we need to be sure to
33   // serialize these.
34   std::vector<const Target*> extra_hard_deps;
35   for (size_t i = 0; i < target_->deps().size(); i++)
36     extra_hard_deps.push_back(target_->deps()[i].ptr);
37
38   // For ACTIONs this is a bit inefficient since it creates an input dep
39   // stamp file even though we're only going to use it once. It would save a
40   // build step to skip this and write the order-only deps directly on the
41   // build rule. This should probably be handled by WriteInputDepsStampAndGetDep
42   // automatically if we supply a count of sources (so it can optimize based on
43   // how many times things would be duplicated).
44   std::string implicit_deps = WriteInputDepsStampAndGetDep(extra_hard_deps);
45   out_ << std::endl;
46
47   // Collects all output files for writing below.
48   std::vector<OutputFile> output_files;
49
50   if (target_->output_type() == Target::ACTION_FOREACH) {
51     // Write separate build lines for each input source file.
52     WriteSourceRules(custom_rule_name, implicit_deps, args_template,
53                      &output_files);
54   } else {
55     DCHECK(target_->output_type() == Target::ACTION);
56
57     // Write a rule that invokes the script once with the outputs as outputs,
58     // and the data as inputs.
59     out_ << "build";
60     if (target_->action_values().has_depfile()) {
61       out_ << " ";
62       WriteDepfile(SourceFile());
63     }
64     const Target::FileList& outputs = target_->action_values().outputs();
65     for (size_t i = 0; i < outputs.size(); i++) {
66       OutputFile output_path(
67           RemovePrefix(outputs[i].value(),
68                        settings_->build_settings()->build_dir().value()));
69       output_files.push_back(output_path);
70       out_ << " ";
71       path_output_.WriteFile(out_, output_path);
72     }
73
74     out_ << ": " << custom_rule_name << implicit_deps << std::endl;
75     if (target_->action_values().has_depfile()) {
76       out_ << "  depfile = ";
77       WriteDepfile(SourceFile());
78       out_ << std::endl;
79     }
80   }
81   out_ << std::endl;
82
83   WriteStamp(output_files);
84 }
85
86 std::string NinjaActionTargetWriter::WriteRuleDefinition(
87     const FileTemplate& args_template) {
88   // Make a unique name for this rule.
89   //
90   // Use a unique name for the response file when there are multiple build
91   // steps so that they don't stomp on each other. When there are no sources,
92   // there will be only one invocation so we can use a simple name.
93   std::string target_label = target_->label().GetUserVisibleName(true);
94   std::string custom_rule_name(target_label);
95   base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
96   custom_rule_name.append("_rule");
97
98   if (settings_->IsWin()) {
99     // Send through gyp-win-tool and use a response file.
100     std::string rspfile = custom_rule_name;
101     if (has_sources())
102       rspfile += ".$unique_name";
103     rspfile += ".rsp";
104
105     out_ << "rule " << custom_rule_name << std::endl;
106     out_ << "  command = ";
107     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
108     // TODO(brettw) this hardcodes "environment.x86" which is something that
109     // the Chrome Windows toolchain writes. We should have a way to invoke
110     // python without requiring this gyp_win_tool thing.
111     out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile
112          << std::endl;
113     out_ << "  description = ACTION " << target_label << std::endl;
114     out_ << "  restat = 1" << std::endl;
115     out_ << "  rspfile = " << rspfile << std::endl;
116
117     // The build command goes in the rsp file.
118     out_ << "  rspfile_content = ";
119     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
120     out_ << " ";
121     path_output_.WriteFile(out_, target_->action_values().script());
122     args_template.WriteWithNinjaExpansions(out_);
123     out_ << std::endl;
124   } else {
125     // Posix can execute Python directly.
126     out_ << "rule " << custom_rule_name << std::endl;
127     out_ << "  command = ";
128     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
129     out_ << " ";
130     path_output_.WriteFile(out_, target_->action_values().script());
131     args_template.WriteWithNinjaExpansions(out_);
132     out_ << std::endl;
133     out_ << "  description = ACTION " << target_label << std::endl;
134     out_ << "  restat = 1" << std::endl;
135   }
136
137   return custom_rule_name;
138 }
139
140 void NinjaActionTargetWriter::WriteArgsSubstitutions(
141     const SourceFile& source,
142     const FileTemplate& args_template) {
143   std::ostringstream source_file_stream;
144   path_output_no_escaping_.WriteFile(source_file_stream, source);
145
146   EscapeOptions template_escape_options;
147   template_escape_options.mode = ESCAPE_NINJA_SHELL;
148   template_escape_options.inhibit_quoting = true;
149
150   args_template.WriteNinjaVariablesForSubstitution(
151       out_, source_file_stream.str(), template_escape_options);
152 }
153
154 void NinjaActionTargetWriter::WriteSourceRules(
155     const std::string& custom_rule_name,
156     const std::string& implicit_deps,
157     const FileTemplate& args_template,
158     std::vector<OutputFile>* output_files) {
159   FileTemplate output_template(GetOutputTemplate());
160
161   const Target::FileList& sources = target_->sources();
162   for (size_t i = 0; i < sources.size(); i++) {
163     out_ << "build";
164     WriteOutputFilesForBuildLine(output_template, sources[i], output_files);
165
166     out_ << ": " << custom_rule_name << " ";
167     path_output_.WriteFile(out_, sources[i]);
168     out_ << implicit_deps << std::endl;
169
170     // Windows needs a unique ID for the response file.
171     if (target_->settings()->IsWin())
172       out_ << "  unique_name = " << i << std::endl;
173
174     if (args_template.has_substitutions())
175       WriteArgsSubstitutions(sources[i], args_template);
176
177     if (target_->action_values().has_depfile()) {
178       out_ << "  depfile = ";
179       WriteDepfile(sources[i]);
180       out_ << std::endl;
181     }
182   }
183 }
184
185 void NinjaActionTargetWriter::WriteStamp(
186     const std::vector<OutputFile>& output_files) {
187   out_ << "build ";
188   path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
189   out_ << ": "
190        << helper_.GetRulePrefix(target_->settings())
191        << "stamp";
192
193   // The action stamp depends on all output files from running the action.
194   for (size_t i = 0; i < output_files.size(); i++) {
195     out_ << " ";
196     path_output_.WriteFile(out_, output_files[i]);
197   }
198
199   // It also depends on all datadeps. These are needed at runtime and should
200   // be compiled when the action is, but don't need to be done before we run
201   // the action.
202   for (size_t i = 0; i < target_->datadeps().size(); i++) {
203     out_ << " ";
204     path_output_.WriteFile(out_,
205         helper_.GetTargetOutputFile(target_->datadeps()[i].ptr));
206   }
207
208   out_ << std::endl;
209 }
210
211 void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
212     const FileTemplate& output_template,
213     const SourceFile& source,
214     std::vector<OutputFile>* output_files) {
215   // If there is a depfile specified we need to list it as the first output as
216   // that is what ninja will expect the depfile to refer to itself as.
217   if (target_->action_values().has_depfile()) {
218     out_ << " ";
219     WriteDepfile(source);
220   }
221   std::vector<std::string> output_template_result;
222   output_template.ApplyString(source.value(), &output_template_result);
223   for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) {
224     OutputFile output_path(output_template_result[out_i]);
225     output_files->push_back(output_path);
226     out_ << " ";
227     path_output_.WriteFile(out_, output_path);
228   }
229 }
230
231 void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
232   std::vector<std::string> result;
233   GetDepfileTemplate().ApplyString(source.value(), &result);
234   path_output_.WriteFile(out_, OutputFile(result[0]));
235 }
236
237 FileTemplate NinjaActionTargetWriter::GetDepfileTemplate() const {
238   std::vector<std::string> template_args;
239   std::string depfile_relative_to_build_dir =
240       RemovePrefix(target_->action_values().depfile().value(),
241                    settings_->build_settings()->build_dir().value());
242   template_args.push_back(depfile_relative_to_build_dir);
243   return FileTemplate(template_args);
244 }