Update To 11.40.268.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/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"
14
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           ESCAPE_NONE) {
21 }
22
23 NinjaActionTargetWriter::~NinjaActionTargetWriter() {
24 }
25
26 void NinjaActionTargetWriter::Run() {
27   std::string custom_rule_name = WriteRuleDefinition();
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 (const auto& pair : target_->GetDeps(Target::DEPS_LINKED))
36     extra_hard_deps.push_back(pair.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   OutputFile input_dep = 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, input_dep, &output_files);
53   } else {
54     DCHECK(target_->output_type() == Target::ACTION);
55
56     // Write a rule that invokes the script once with the outputs as outputs,
57     // and the data as inputs. It does not depend on the sources.
58     out_ << "build";
59     SubstitutionWriter::GetListAsOutputFiles(
60         settings_, target_->action_values().outputs(), &output_files);
61     path_output_.WriteFiles(out_, output_files);
62
63     out_ << ": " << custom_rule_name;
64     if (!input_dep.value().empty()) {
65       // As in WriteSourceRules, we want to force this target to rebuild any
66       // time any of its dependencies change.
67       out_ << " | ";
68       path_output_.WriteFile(out_, input_dep);
69     }
70     out_ << std::endl;
71     if (target_->action_values().has_depfile()) {
72       out_ << "  depfile = ";
73       WriteDepfile(SourceFile());
74       out_ << std::endl;
75     }
76   }
77   out_ << std::endl;
78
79   // Write the stamp, which also depends on all data deps. These are needed at
80   // runtime and should be compiled when the action is, but don't need to be
81   // done before we run the action.
82   std::vector<OutputFile> data_outs;
83   for (const auto& dep : target_->data_deps())
84     data_outs.push_back(dep.ptr->dependency_output_file());
85   WriteStampForTarget(output_files, data_outs);
86 }
87
88 std::string NinjaActionTargetWriter::WriteRuleDefinition() {
89   // Make a unique name for this rule.
90   //
91   // Use a unique name for the response file when there are multiple build
92   // steps so that they don't stomp on each other. When there are no sources,
93   // there will be only one invocation so we can use a simple name.
94   std::string target_label = target_->label().GetUserVisibleName(true);
95   std::string custom_rule_name(target_label);
96   base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
97   custom_rule_name.append("_rule");
98
99   const SubstitutionList& args = target_->action_values().args();
100   EscapeOptions args_escape_options;
101   args_escape_options.mode = ESCAPE_NINJA_COMMAND;
102
103   if (settings_->IsWin()) {
104     // Send through gyp-win-tool and use a response file.
105     std::string rspfile = custom_rule_name;
106     if (!target_->sources().empty())
107       rspfile += ".$unique_name";
108     rspfile += ".rsp";
109
110     out_ << "rule " << custom_rule_name << std::endl;
111     out_ << "  command = ";
112     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
113     // TODO(brettw) this hardcodes "environment.x86" which is something that
114     // the Chrome Windows toolchain writes. We should have a way to invoke
115     // python without requiring this gyp_win_tool thing.
116     out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile
117          << std::endl;
118     out_ << "  description = ACTION " << target_label << std::endl;
119     out_ << "  restat = 1" << std::endl;
120     out_ << "  rspfile = " << rspfile << std::endl;
121
122     // The build command goes in the rsp file.
123     out_ << "  rspfile_content = ";
124     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
125     out_ << " ";
126     path_output_.WriteFile(out_, target_->action_values().script());
127     for (const auto& arg : args.list()) {
128       out_ << " ";
129       SubstitutionWriter::WriteWithNinjaVariables(
130           arg, args_escape_options, out_);
131     }
132     out_ << std::endl;
133   } else {
134     // Posix can execute Python directly.
135     out_ << "rule " << custom_rule_name << std::endl;
136     out_ << "  command = ";
137     path_output_.WriteFile(out_, settings_->build_settings()->python_path());
138     out_ << " ";
139     path_output_.WriteFile(out_, target_->action_values().script());
140     for (const auto& arg : args.list()) {
141       out_ << " ";
142       SubstitutionWriter::WriteWithNinjaVariables(
143           arg, args_escape_options, out_);
144     }
145     out_ << std::endl;
146     out_ << "  description = ACTION " << target_label << std::endl;
147     out_ << "  restat = 1" << std::endl;
148   }
149
150   return custom_rule_name;
151 }
152
153 void NinjaActionTargetWriter::WriteSourceRules(
154     const std::string& custom_rule_name,
155     const OutputFile& input_dep,
156     std::vector<OutputFile>* output_files) {
157   EscapeOptions args_escape_options;
158   args_escape_options.mode = ESCAPE_NINJA_COMMAND;
159   // We're writing the substitution values, these should not be quoted since
160   // they will get pasted into the real command line.
161   args_escape_options.inhibit_quoting = true;
162
163   const std::vector<SubstitutionType>& args_substitutions_used =
164       target_->action_values().args().required_types();
165
166   const Target::FileList& sources = target_->sources();
167   for (size_t i = 0; i < sources.size(); i++) {
168     out_ << "build";
169     WriteOutputFilesForBuildLine(sources[i], output_files);
170
171     out_ << ": " << custom_rule_name << " ";
172     path_output_.WriteFile(out_, sources[i]);
173     if (!input_dep.value().empty()) {
174       // Using "|" for the dependencies forces all implicit dependencies to be
175       // fully up-to-date before running the action, and will re-run this
176       // action if any input dependencies change. This is important because
177       // this action may consume the outputs of previous steps.
178       out_ << " | ";
179       path_output_.WriteFile(out_, input_dep);
180     }
181     out_ << std::endl;
182
183     // Windows needs a unique ID for the response file.
184     if (target_->settings()->IsWin())
185       out_ << "  unique_name = " << i << std::endl;
186
187     SubstitutionWriter::WriteNinjaVariablesForSource(
188         settings_, sources[i], args_substitutions_used,
189         args_escape_options, out_);
190
191     if (target_->action_values().has_depfile()) {
192       out_ << "  depfile = ";
193       WriteDepfile(sources[i]);
194       out_ << std::endl;
195     }
196   }
197 }
198
199 void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
200     const SourceFile& source,
201     std::vector<OutputFile>* output_files) {
202   size_t first_output_index = output_files->size();
203
204   SubstitutionWriter::ApplyListToSourceAsOutputFile(
205       settings_, target_->action_values().outputs(), source, output_files);
206
207   for (size_t i = first_output_index; i < output_files->size(); i++) {
208     out_ << " ";
209     path_output_.WriteFile(out_, (*output_files)[i]);
210   }
211 }
212
213 void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
214   path_output_.WriteFile(out_,
215       SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
216           settings_, target_->action_values().depfile(), source));
217 }