Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(387)

Side by Side Diff: tools/gn/ninja_action_target_writer.cc

Issue 429423002: Refactor GN source expansions. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/ninja_action_target_writer.h ('k') | tools/gn/ninja_action_target_writer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "tools/gn/ninja_action_target_writer.h" 5 #include "tools/gn/ninja_action_target_writer.h"
6 6
7 #include "base/strings/string_util.h" 7 #include "base/strings/string_util.h"
8 #include "tools/gn/err.h" 8 #include "tools/gn/err.h"
9 #include "tools/gn/file_template.h"
10 #include "tools/gn/string_utils.h" 9 #include "tools/gn/string_utils.h"
10 #include "tools/gn/substitution_writer.h"
11 #include "tools/gn/target.h" 11 #include "tools/gn/target.h"
12 12
13 NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target, 13 NinjaActionTargetWriter::NinjaActionTargetWriter(const Target* target,
14 const Toolchain* toolchain, 14 const Toolchain* toolchain,
15 std::ostream& out) 15 std::ostream& out)
16 : NinjaTargetWriter(target, toolchain, out), 16 : NinjaTargetWriter(target, toolchain, out),
17 path_output_no_escaping_( 17 path_output_no_escaping_(
18 target->settings()->build_settings()->build_dir(), 18 target->settings()->build_settings()->build_dir(),
19 ESCAPE_NONE) { 19 ESCAPE_NONE) {
20 } 20 }
21 21
22 NinjaActionTargetWriter::~NinjaActionTargetWriter() { 22 NinjaActionTargetWriter::~NinjaActionTargetWriter() {
23 } 23 }
24 24
25 void NinjaActionTargetWriter::Run() { 25 void NinjaActionTargetWriter::Run() {
26 FileTemplate args_template( 26 std::string custom_rule_name = WriteRuleDefinition();
27 target_->settings(),
28 target_->action_values().args(),
29 FileTemplate::OUTPUT_RELATIVE,
30 target_->settings()->build_settings()->build_dir());
31 std::string custom_rule_name = WriteRuleDefinition(args_template);
32 27
33 // Collect our deps to pass as "extra hard dependencies" for input deps. This 28 // Collect our deps to pass as "extra hard dependencies" for input deps. This
34 // will force all of the action's dependencies to be completed before the 29 // will force all of the action's dependencies to be completed before the
35 // action is run. Usually, if an action has a dependency, it will be 30 // action is run. Usually, if an action has a dependency, it will be
36 // operating on the result of that previous step, so we need to be sure to 31 // operating on the result of that previous step, so we need to be sure to
37 // serialize these. 32 // serialize these.
38 std::vector<const Target*> extra_hard_deps; 33 std::vector<const Target*> extra_hard_deps;
39 for (size_t i = 0; i < target_->deps().size(); i++) 34 for (size_t i = 0; i < target_->deps().size(); i++)
40 extra_hard_deps.push_back(target_->deps()[i].ptr); 35 extra_hard_deps.push_back(target_->deps()[i].ptr);
41 36
42 // For ACTIONs this is a bit inefficient since it creates an input dep 37 // For ACTIONs this is a bit inefficient since it creates an input dep
43 // stamp file even though we're only going to use it once. It would save a 38 // stamp file even though we're only going to use it once. It would save a
44 // build step to skip this and write the order-only deps directly on the 39 // build step to skip this and write the order-only deps directly on the
45 // build rule. This should probably be handled by WriteInputDepsStampAndGetDep 40 // build rule. This should probably be handled by WriteInputDepsStampAndGetDep
46 // automatically if we supply a count of sources (so it can optimize based on 41 // automatically if we supply a count of sources (so it can optimize based on
47 // how many times things would be duplicated). 42 // how many times things would be duplicated).
48 std::string implicit_deps = WriteInputDepsStampAndGetDep(extra_hard_deps); 43 std::string implicit_deps = WriteInputDepsStampAndGetDep(extra_hard_deps);
49 out_ << std::endl; 44 out_ << std::endl;
50 45
51 // Collects all output files for writing below. 46 // Collects all output files for writing below.
52 std::vector<OutputFile> output_files; 47 std::vector<OutputFile> output_files;
53 48
54 if (target_->output_type() == Target::ACTION_FOREACH) { 49 if (target_->output_type() == Target::ACTION_FOREACH) {
55 // Write separate build lines for each input source file. 50 // Write separate build lines for each input source file.
56 WriteSourceRules(custom_rule_name, implicit_deps, args_template, 51 WriteSourceRules(custom_rule_name, implicit_deps, &output_files);
57 &output_files);
58 } else { 52 } else {
59 DCHECK(target_->output_type() == Target::ACTION); 53 DCHECK(target_->output_type() == Target::ACTION);
60 54
61 // Write a rule that invokes the script once with the outputs as outputs, 55 // Write a rule that invokes the script once with the outputs as outputs,
62 // and the data as inputs. 56 // and the data as inputs.
63 out_ << "build"; 57 out_ << "build";
64 const std::vector<std::string>& outputs = 58 SubstitutionWriter::ApplyListToSourcesAsOutputFile(
65 target_->action_values().outputs(); 59 settings_, target_->action_values().outputs(), target_->sources(),
66 for (size_t i = 0; i < outputs.size(); i++) { 60 &output_files);
67 OutputFile output_path( 61 for (size_t i = 0; i < output_files.size(); i++) {
68 RemovePrefix(outputs[i],
69 settings_->build_settings()->build_dir().value()));
70 output_files.push_back(output_path);
71 out_ << " "; 62 out_ << " ";
72 path_output_.WriteFile(out_, output_path); 63 path_output_.WriteFile(out_, output_files[i]);
73 } 64 }
74 65
75 out_ << ": " << custom_rule_name << implicit_deps << std::endl; 66 out_ << ": " << custom_rule_name << implicit_deps << std::endl;
76 if (target_->action_values().has_depfile()) { 67 if (target_->action_values().has_depfile()) {
77 out_ << " depfile = "; 68 out_ << " depfile = ";
78 WriteDepfile(SourceFile()); 69 WriteDepfile(SourceFile());
79 out_ << std::endl; 70 out_ << std::endl;
80 } 71 }
81 } 72 }
82 out_ << std::endl; 73 out_ << std::endl;
83 74
84 WriteStamp(output_files); 75 WriteStamp(output_files);
85 } 76 }
86 77
87 std::string NinjaActionTargetWriter::WriteRuleDefinition( 78 std::string NinjaActionTargetWriter::WriteRuleDefinition() {
88 const FileTemplate& args_template) {
89 // Make a unique name for this rule. 79 // Make a unique name for this rule.
90 // 80 //
91 // Use a unique name for the response file when there are multiple build 81 // 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, 82 // 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. 83 // there will be only one invocation so we can use a simple name.
94 std::string target_label = target_->label().GetUserVisibleName(true); 84 std::string target_label = target_->label().GetUserVisibleName(true);
95 std::string custom_rule_name(target_label); 85 std::string custom_rule_name(target_label);
96 base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name); 86 base::ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
97 custom_rule_name.append("_rule"); 87 custom_rule_name.append("_rule");
98 88
89 const SubstitutionList& args = target_->action_values().args();
90 EscapeOptions args_escape_options;
91 args_escape_options.mode = ESCAPE_NINJA_COMMAND;
92
99 if (settings_->IsWin()) { 93 if (settings_->IsWin()) {
100 // Send through gyp-win-tool and use a response file. 94 // Send through gyp-win-tool and use a response file.
101 std::string rspfile = custom_rule_name; 95 std::string rspfile = custom_rule_name;
102 if (has_sources()) 96 if (has_sources())
103 rspfile += ".$unique_name"; 97 rspfile += ".$unique_name";
104 rspfile += ".rsp"; 98 rspfile += ".rsp";
105 99
106 out_ << "rule " << custom_rule_name << std::endl; 100 out_ << "rule " << custom_rule_name << std::endl;
107 out_ << " command = "; 101 out_ << " command = ";
108 path_output_.WriteFile(out_, settings_->build_settings()->python_path()); 102 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
109 // TODO(brettw) this hardcodes "environment.x86" which is something that 103 // TODO(brettw) this hardcodes "environment.x86" which is something that
110 // the Chrome Windows toolchain writes. We should have a way to invoke 104 // the Chrome Windows toolchain writes. We should have a way to invoke
111 // python without requiring this gyp_win_tool thing. 105 // python without requiring this gyp_win_tool thing.
112 out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile 106 out_ << " gyp-win-tool action-wrapper environment.x86 " << rspfile
113 << std::endl; 107 << std::endl;
114 out_ << " description = ACTION " << target_label << std::endl; 108 out_ << " description = ACTION " << target_label << std::endl;
115 out_ << " restat = 1" << std::endl; 109 out_ << " restat = 1" << std::endl;
116 out_ << " rspfile = " << rspfile << std::endl; 110 out_ << " rspfile = " << rspfile << std::endl;
117 111
118 // The build command goes in the rsp file. 112 // The build command goes in the rsp file.
119 out_ << " rspfile_content = "; 113 out_ << " rspfile_content = ";
120 path_output_.WriteFile(out_, settings_->build_settings()->python_path()); 114 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
121 out_ << " "; 115 out_ << " ";
122 path_output_.WriteFile(out_, target_->action_values().script()); 116 path_output_.WriteFile(out_, target_->action_values().script());
123 args_template.WriteWithNinjaExpansions(out_); 117 for (size_t i = 0; i < args.list().size(); i++) {
118 out_ << " ";
119 SubstitutionWriter::WriteWithNinjaVariables(
120 args.list()[i], args_escape_options, out_);
121 }
124 out_ << std::endl; 122 out_ << std::endl;
125 } else { 123 } else {
126 // Posix can execute Python directly. 124 // Posix can execute Python directly.
127 out_ << "rule " << custom_rule_name << std::endl; 125 out_ << "rule " << custom_rule_name << std::endl;
128 out_ << " command = "; 126 out_ << " command = ";
129 path_output_.WriteFile(out_, settings_->build_settings()->python_path()); 127 path_output_.WriteFile(out_, settings_->build_settings()->python_path());
130 out_ << " "; 128 out_ << " ";
131 path_output_.WriteFile(out_, target_->action_values().script()); 129 path_output_.WriteFile(out_, target_->action_values().script());
132 args_template.WriteWithNinjaExpansions(out_); 130 for (size_t i = 0; i < args.list().size(); i++) {
131 out_ << " ";
132 SubstitutionWriter::WriteWithNinjaVariables(
133 args.list()[i], args_escape_options, out_);
134 }
133 out_ << std::endl; 135 out_ << std::endl;
134 out_ << " description = ACTION " << target_label << std::endl; 136 out_ << " description = ACTION " << target_label << std::endl;
135 out_ << " restat = 1" << std::endl; 137 out_ << " restat = 1" << std::endl;
136 } 138 }
137 139
138 return custom_rule_name; 140 return custom_rule_name;
139 } 141 }
140 142
141 void NinjaActionTargetWriter::WriteArgsSubstitutions(
142 const SourceFile& source,
143 const FileTemplate& args_template) {
144 EscapeOptions template_escape_options;
145 template_escape_options.mode = ESCAPE_NINJA_COMMAND;
146
147 args_template.WriteNinjaVariablesForSubstitution(
148 out_, source, template_escape_options);
149 }
150
151 void NinjaActionTargetWriter::WriteSourceRules( 143 void NinjaActionTargetWriter::WriteSourceRules(
152 const std::string& custom_rule_name, 144 const std::string& custom_rule_name,
153 const std::string& implicit_deps, 145 const std::string& implicit_deps,
154 const FileTemplate& args_template,
155 std::vector<OutputFile>* output_files) { 146 std::vector<OutputFile>* output_files) {
156 FileTemplate output_template = FileTemplate::GetForTargetOutputs(target_); 147 EscapeOptions args_escape_options;
148 args_escape_options.mode = ESCAPE_NINJA_COMMAND;
149 // We're writing the substitution values, these should not be quoted since
150 // they will get pasted into the real command line.
151 args_escape_options.inhibit_quoting = true;
152
153 const std::vector<SubstitutionType>& args_substitutions_used =
154 target_->action_values().args().required_types();
157 155
158 const Target::FileList& sources = target_->sources(); 156 const Target::FileList& sources = target_->sources();
159 for (size_t i = 0; i < sources.size(); i++) { 157 for (size_t i = 0; i < sources.size(); i++) {
160 out_ << "build"; 158 out_ << "build";
161 WriteOutputFilesForBuildLine(output_template, sources[i], output_files); 159 WriteOutputFilesForBuildLine(sources[i], output_files);
162 160
163 out_ << ": " << custom_rule_name << " "; 161 out_ << ": " << custom_rule_name << " ";
164 path_output_.WriteFile(out_, sources[i]); 162 path_output_.WriteFile(out_, sources[i]);
165 out_ << implicit_deps << std::endl; 163 out_ << implicit_deps << std::endl;
166 164
167 // Windows needs a unique ID for the response file. 165 // Windows needs a unique ID for the response file.
168 if (target_->settings()->IsWin()) 166 if (target_->settings()->IsWin())
169 out_ << " unique_name = " << i << std::endl; 167 out_ << " unique_name = " << i << std::endl;
170 168
171 if (args_template.has_substitutions()) 169 SubstitutionWriter::WriteNinjaVariablesForSource(
172 WriteArgsSubstitutions(sources[i], args_template); 170 settings_, sources[i], args_substitutions_used,
171 args_escape_options, out_);
173 172
174 if (target_->action_values().has_depfile()) { 173 if (target_->action_values().has_depfile()) {
175 out_ << " depfile = "; 174 out_ << " depfile = ";
176 WriteDepfile(sources[i]); 175 WriteDepfile(sources[i]);
177 out_ << std::endl; 176 out_ << std::endl;
178 } 177 }
179 } 178 }
180 } 179 }
181 180
182 void NinjaActionTargetWriter::WriteStamp( 181 void NinjaActionTargetWriter::WriteStamp(
(...skipping 16 matching lines...) Expand all
199 for (size_t i = 0; i < target_->datadeps().size(); i++) { 198 for (size_t i = 0; i < target_->datadeps().size(); i++) {
200 out_ << " "; 199 out_ << " ";
201 path_output_.WriteFile(out_, 200 path_output_.WriteFile(out_,
202 helper_.GetTargetOutputFile(target_->datadeps()[i].ptr)); 201 helper_.GetTargetOutputFile(target_->datadeps()[i].ptr));
203 } 202 }
204 203
205 out_ << std::endl; 204 out_ << std::endl;
206 } 205 }
207 206
208 void NinjaActionTargetWriter::WriteOutputFilesForBuildLine( 207 void NinjaActionTargetWriter::WriteOutputFilesForBuildLine(
209 const FileTemplate& output_template,
210 const SourceFile& source, 208 const SourceFile& source,
211 std::vector<OutputFile>* output_files) { 209 std::vector<OutputFile>* output_files) {
212 std::vector<std::string> output_template_result; 210 size_t first_output_index = output_files->size();
213 output_template.Apply(source, &output_template_result); 211
214 for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) { 212 SubstitutionWriter::ApplyListToSourceAsOutputFile(
215 // All output files should be in the build directory, so we can rebase 213 settings_, target_->action_values().outputs(), source, output_files);
216 // them just by trimming the prefix. 214
217 OutputFile output_path( 215 for (size_t i = first_output_index; i < output_files->size(); i++) {
218 RemovePrefix(output_template_result[out_i],
219 settings_->build_settings()->build_dir().value()));
220 output_files->push_back(output_path);
221 out_ << " "; 216 out_ << " ";
222 path_output_.WriteFile(out_, output_path); 217 path_output_.WriteFile(out_, (*output_files)[i]);
223 } 218 }
224 } 219 }
225 220
226 void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) { 221 void NinjaActionTargetWriter::WriteDepfile(const SourceFile& source) {
227 std::vector<std::string> result; 222 path_output_.WriteFile(out_,
228 GetDepfileTemplate().Apply(source, &result); 223 SubstitutionWriter::ApplyPatternToSourceAsOutputFile(
229 path_output_.WriteFile(out_, OutputFile(result[0])); 224 settings_, target_->action_values().depfile(), source));
230 } 225 }
231
232 FileTemplate NinjaActionTargetWriter::GetDepfileTemplate() const {
233 std::vector<std::string> template_args;
234 std::string depfile_relative_to_build_dir =
235 RemovePrefix(target_->action_values().depfile().value(),
236 settings_->build_settings()->build_dir().value());
237 template_args.push_back(depfile_relative_to_build_dir);
238 return FileTemplate(settings_, template_args, FileTemplate::OUTPUT_ABSOLUTE,
239 SourceDir());
240 }
OLDNEW
« no previous file with comments | « tools/gn/ninja_action_target_writer.h ('k') | tools/gn/ninja_action_target_writer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698