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

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

Issue 387663003: Improve GN handling of directory templates. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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/file_template.h ('k') | tools/gn/file_template_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/file_template.h" 5 #include "tools/gn/file_template.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iostream> 8 #include <iostream>
9 9
10 #include "tools/gn/escape.h" 10 #include "tools/gn/escape.h"
(...skipping 26 matching lines...) Expand all
37 " If no placeholders are found, the outputs or args list will be treated\n" 37 " If no placeholders are found, the outputs or args list will be treated\n"
38 " as a static list of literal file names that do not depend on the\n" 38 " as a static list of literal file names that do not depend on the\n"
39 " sources.\n" 39 " sources.\n"
40 "\n" 40 "\n"
41 " See \"gn help copy\" and \"gn help action_foreach\" for more on how\n" 41 " See \"gn help copy\" and \"gn help action_foreach\" for more on how\n"
42 " this is applied.\n" 42 " this is applied.\n"
43 "\n" 43 "\n"
44 "Placeholders\n" 44 "Placeholders\n"
45 "\n" 45 "\n"
46 " {{source}}\n" 46 " {{source}}\n"
47 " The name of the source file relative to the root build output\n" 47 " The name of the source file including directory (*). This will\n"
48 " directory (which is the current directory when running compilers\n" 48 " generally be used for specifying inputs to a script in the\n"
49 " and scripts). This will generally be used for specifying inputs\n" 49 " \"args\" variable.\n"
50 " to a script in the \"args\" variable.\n"
51 " \"//foo/bar/baz.txt\" => \"../../foo/bar/baz.txt\"\n" 50 " \"//foo/bar/baz.txt\" => \"../../foo/bar/baz.txt\"\n"
52 "\n" 51 "\n"
53 " {{source_file_part}}\n" 52 " {{source_file_part}}\n"
54 " The file part of the source including the extension.\n" 53 " The file part of the source including the extension.\n"
55 " \"//foo/bar/baz.txt\" => \"baz.txt\"\n" 54 " \"//foo/bar/baz.txt\" => \"baz.txt\"\n"
56 "\n" 55 "\n"
57 " {{source_name_part}}\n" 56 " {{source_name_part}}\n"
58 " The filename part of the source file with no directory or\n" 57 " The filename part of the source file with no directory or\n"
59 " extension. This will generally be used for specifying a\n" 58 " extension. This will generally be used for specifying a\n"
60 " transformation from a soruce file to a destination file with the\n" 59 " transformation from a soruce file to a destination file with the\n"
61 " same name but different extension.\n" 60 " same name but different extension.\n"
62 " \"//foo/bar/baz.txt\" => \"baz\"\n" 61 " \"//foo/bar/baz.txt\" => \"baz\"\n"
63 "\n" 62 "\n"
64 " {{source_dir}}\n" 63 " {{source_dir}}\n"
65 " The directory containing the source file, relative to the build\n" 64 " The directory (*) containing the source file with no\n"
66 " directory, with no trailing slash.\n" 65 " trailing slash.\n"
67 " \"//foo/bar/baz.txt\" => \"../../foo/bar\"\n" 66 " \"//foo/bar/baz.txt\" => \"../../foo/bar\"\n"
68 "\n" 67 "\n"
69 " {{source_root_relative_dir}}\n" 68 " {{source_root_relative_dir}}\n"
70 " The path to the source file's directory relative to the source\n" 69 " The path to the source file's directory relative to the source\n"
71 " root, with no leading \"//\" or trailing slashes. If the path is\n" 70 " root, with no leading \"//\" or trailing slashes. If the path is\n"
72 " system-absolute, (beginning in a single slash) this will just\n" 71 " system-absolute, (beginning in a single slash) this will just\n"
73 " return the path with no trailing slash.\n" 72 " return the path with no trailing slash. This value will always\n"
73 " be the same, regardless of whether it appears in the \"outputs\"\n"
74 " or \"args\" section.\n"
74 " \"//foo/bar/baz.txt\" => \"foo/bar\"\n" 75 " \"//foo/bar/baz.txt\" => \"foo/bar\"\n"
75 "\n" 76 "\n"
76 " {{source_gen_dir}}\n" 77 " {{source_gen_dir}}\n"
77 " The generated file directory corresponding to the source file's\n" 78 " The generated file directory (*) corresponding to the source\n"
78 " path, relative to the build directory. This will be different than\n" 79 " file's path. This will be different than the target's generated\n"
79 " the target's generated file directory if the source file is in a\n" 80 " file directory if the source file is in a different directory\n"
80 " different directory than the build.gn file. If the input path is\n" 81 " than the BUILD.gn file.\n"
81 " system absolute, this will return the root generated file\n"
82 " directory."
83 " \"//foo/bar/baz.txt\" => \"gen/foo/bar\"\n" 82 " \"//foo/bar/baz.txt\" => \"gen/foo/bar\"\n"
84 "\n" 83 "\n"
85 " {{source_out_dir}}\n" 84 " {{source_out_dir}}\n"
86 " The object file directory corresponding to the source file's\n" 85 " The object file directory (*) corresponding to the source file's\n"
87 " path, relative to the build directory. this us be different than\n" 86 " path, relative to the build directory. this us be different than\n"
88 " the target's out directory if the source file is in a different\n" 87 " the target's out directory if the source file is in a different\n"
89 " directory than the build.gn file. if the input path is system\n" 88 " directory than the build.gn file.\n"
90 " absolute, this will return the root generated file directory.\n"
91 " \"//foo/bar/baz.txt\" => \"obj/foo/bar\"\n" 89 " \"//foo/bar/baz.txt\" => \"obj/foo/bar\"\n"
92 "\n" 90 "\n"
91 "(*) Note on directories\n"
92 "\n"
93 " Paths containing directories (except the source_root_relative_dir)\n"
94 " will be different depending on what context the expansion is evaluated\n"
95 " in. Generally it should \"just work\" but it means you can't\n"
96 " concatenate strings containing these values with reasonable results.\n"
97 "\n"
98 " Details: source expansions can be used in the \"outputs\" variable,\n"
99 " the \"args\" variable, and in calls to \"process_file_template\". The\n"
100 " \"args\" are passed to a script which is run from the build directory,\n"
101 " so these directories will relative to the build directory for the\n"
102 " script to find. In the other cases, the directories will be source-\n"
103 " absolute (begin with a \"//\") because the results of those expansions\n"
104 " will be handled by GN internally.\n"
105 "\n"
93 "Examples\n" 106 "Examples\n"
94 "\n" 107 "\n"
95 " Non-varying outputs:\n" 108 " Non-varying outputs:\n"
96 " action(\"hardcoded_outputs\") {\n" 109 " action(\"hardcoded_outputs\") {\n"
97 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" 110 " sources = [ \"input1.idl\", \"input2.idl\" ]\n"
98 " outputs = [ \"$target_out_dir/output1.dat\",\n" 111 " outputs = [ \"$target_out_dir/output1.dat\",\n"
99 " \"$target_out_dir/output2.dat\" ]\n" 112 " \"$target_out_dir/output2.dat\" ]\n"
100 " }\n" 113 " }\n"
101 " The outputs in this case will be the two literal files given.\n" 114 " The outputs in this case will be the two literal files given.\n"
102 "\n" 115 "\n"
103 " Varying outputs:\n" 116 " Varying outputs:\n"
104 " action_foreach(\"varying_outputs\") {\n" 117 " action_foreach(\"varying_outputs\") {\n"
105 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" 118 " sources = [ \"input1.idl\", \"input2.idl\" ]\n"
106 " outputs = [ \"$target_out_dir/{{source_name_part}}.h\",\n" 119 " outputs = [ \"{{source_gen_dir}}/{{source_name_part}}.h\",\n"
107 " \"$target_out_dir/{{source_name_part}}.cc\" ]\n" 120 " \"{{source_gen_dir}}/{{source_name_part}}.cc\" ]\n"
108 " }\n" 121 " }\n"
109 " Performing source expansion will result in the following output names:\n" 122 " Performing source expansion will result in the following output names:\n"
110 " //out/Debug/obj/mydirectory/input1.h\n" 123 " //out/Debug/obj/mydirectory/input1.h\n"
111 " //out/Debug/obj/mydirectory/input1.cc\n" 124 " //out/Debug/obj/mydirectory/input1.cc\n"
112 " //out/Debug/obj/mydirectory/input2.h\n" 125 " //out/Debug/obj/mydirectory/input2.h\n"
113 " //out/Debug/obj/mydirectory/input2.cc\n"; 126 " //out/Debug/obj/mydirectory/input2.cc\n";
114 127
115 FileTemplate::FileTemplate(const Settings* settings, const Value& t, Err* err) 128 FileTemplate::FileTemplate(const Settings* settings,
129 const Value& t,
130 OutputStyle output_style,
131 const SourceDir& relative_to,
132 Err* err)
116 : settings_(settings), 133 : settings_(settings),
134 output_style_(output_style),
135 relative_to_(relative_to),
117 has_substitutions_(false) { 136 has_substitutions_(false) {
118 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); 137 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
119 ParseInput(t, err); 138 ParseInput(t, err);
120 } 139 }
121 140
122 FileTemplate::FileTemplate(const Settings* settings, 141 FileTemplate::FileTemplate(const Settings* settings,
123 const std::vector<std::string>& t) 142 const std::vector<std::string>& t,
143 OutputStyle output_style,
144 const SourceDir& relative_to)
124 : settings_(settings), 145 : settings_(settings),
146 output_style_(output_style),
147 relative_to_(relative_to),
125 has_substitutions_(false) { 148 has_substitutions_(false) {
126 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); 149 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
127 for (size_t i = 0; i < t.size(); i++) 150 for (size_t i = 0; i < t.size(); i++)
128 ParseOneTemplateString(t[i]); 151 ParseOneTemplateString(t[i]);
129 } 152 }
130 153
131 FileTemplate::FileTemplate(const Settings* settings, 154 FileTemplate::FileTemplate(const Settings* settings,
132 const std::vector<SourceFile>& t) 155 const std::vector<SourceFile>& t,
156 OutputStyle output_style,
157 const SourceDir& relative_to)
133 : settings_(settings), 158 : settings_(settings),
159 output_style_(output_style),
160 relative_to_(relative_to),
134 has_substitutions_(false) { 161 has_substitutions_(false) {
135 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); 162 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
136 for (size_t i = 0; i < t.size(); i++) 163 for (size_t i = 0; i < t.size(); i++)
137 ParseOneTemplateString(t[i].value()); 164 ParseOneTemplateString(t[i].value());
138 } 165 }
139 166
140 FileTemplate::~FileTemplate() { 167 FileTemplate::~FileTemplate() {
141 } 168 }
142 169
143 // static 170 // static
144 FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) { 171 FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) {
145 const Target::FileList& outputs = target->action_values().outputs(); 172 const std::vector<std::string>& outputs = target->action_values().outputs();
146 std::vector<std::string> output_template_args; 173 std::vector<std::string> output_template_args;
147 for (size_t i = 0; i < outputs.size(); i++) 174 for (size_t i = 0; i < outputs.size(); i++)
148 output_template_args.push_back(outputs[i].value()); 175 output_template_args.push_back(outputs[i]);
149 return FileTemplate(target->settings(), output_template_args); 176 return FileTemplate(target->settings(), output_template_args,
177 OUTPUT_ABSOLUTE, SourceDir());
150 } 178 }
151 179
152 bool FileTemplate::IsTypeUsed(Subrange::Type type) const { 180 bool FileTemplate::IsTypeUsed(Subrange::Type type) const {
153 DCHECK(type > Subrange::LITERAL && type < Subrange::NUM_TYPES); 181 DCHECK(type > Subrange::LITERAL && type < Subrange::NUM_TYPES);
154 return types_required_[type]; 182 return types_required_[type];
155 } 183 }
156 184
157 void FileTemplate::Apply(const SourceFile& source, 185 void FileTemplate::Apply(const SourceFile& source,
158 std::vector<std::string>* output) const { 186 std::vector<std::string>* output) const {
159 // Compute all substitutions needed so we can just do substitutions below. 187 // Compute all substitutions needed so we can just do substitutions below.
160 // We skip the LITERAL one since that varies each time. 188 // We skip the LITERAL one since that varies each time.
161 std::string subst[Subrange::NUM_TYPES]; 189 std::string subst[Subrange::NUM_TYPES];
162 for (int i = 1; i < Subrange::NUM_TYPES; i++) { 190 for (int i = 1; i < Subrange::NUM_TYPES; i++) {
163 if (types_required_[i]) { 191 if (types_required_[i]) {
164 subst[i] = 192 subst[i] = GetSubstitution(settings_, source,
165 GetSubstitution(settings_, source, static_cast<Subrange::Type>(i)); 193 static_cast<Subrange::Type>(i),
194 output_style_, relative_to_);
166 } 195 }
167 } 196 }
168 197
169 size_t first_output_index = output->size(); 198 size_t first_output_index = output->size();
170 output->resize(output->size() + templates_.container().size()); 199 output->resize(output->size() + templates_.container().size());
171 for (size_t template_i = 0; 200 for (size_t template_i = 0;
172 template_i < templates_.container().size(); template_i++) { 201 template_i < templates_.container().size(); template_i++) {
173 const Template& t = templates_[template_i]; 202 const Template& t = templates_[template_i];
174 std::string& cur_output = (*output)[first_output_index + template_i]; 203 std::string& cur_output = (*output)[first_output_index + template_i];
175 for (size_t subrange_i = 0; subrange_i < t.container().size(); 204 for (size_t subrange_i = 0; subrange_i < t.container().size();
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 // argument. 249 // argument.
221 out << '"' << item_str << '"'; 250 out << '"' << item_str << '"';
222 } else { 251 } else {
223 out << item_str; 252 out << item_str;
224 } 253 }
225 } 254 }
226 } 255 }
227 256
228 void FileTemplate::WriteNinjaVariablesForSubstitution( 257 void FileTemplate::WriteNinjaVariablesForSubstitution(
229 std::ostream& out, 258 std::ostream& out,
230 const Settings* settings,
231 const SourceFile& source, 259 const SourceFile& source,
232 const EscapeOptions& escape_options) const { 260 const EscapeOptions& escape_options) const {
233 for (int i = 1; i < Subrange::NUM_TYPES; i++) { 261 for (int i = 1; i < Subrange::NUM_TYPES; i++) {
234 if (types_required_[i]) { 262 if (types_required_[i]) {
235 Subrange::Type type = static_cast<Subrange::Type>(i); 263 Subrange::Type type = static_cast<Subrange::Type>(i);
236 out << " " << GetNinjaVariableNameForType(type) << " = "; 264 out << " " << GetNinjaVariableNameForType(type) << " = ";
237 EscapeStringToStream(out, GetSubstitution(settings, source, type), 265 EscapeStringToStream(
238 escape_options); 266 out,
267 GetSubstitution(settings_, source, type, output_style_, relative_to_),
268 escape_options);
239 out << std::endl; 269 out << std::endl;
240 } 270 }
241 } 271 }
242 } 272 }
243 273
244 // static 274 // static
245 const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) { 275 const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) {
246 switch (type) { 276 switch (type) {
247 case Subrange::SOURCE: 277 case Subrange::SOURCE:
248 return "source"; 278 return "source";
(...skipping 12 matching lines...) Expand all
261 291
262 default: 292 default:
263 NOTREACHED(); 293 NOTREACHED();
264 } 294 }
265 return ""; 295 return "";
266 } 296 }
267 297
268 // static 298 // static
269 std::string FileTemplate::GetSubstitution(const Settings* settings, 299 std::string FileTemplate::GetSubstitution(const Settings* settings,
270 const SourceFile& source, 300 const SourceFile& source,
271 Subrange::Type type) { 301 Subrange::Type type,
302 OutputStyle output_style,
303 const SourceDir& relative_to) {
304 std::string to_rebase;
272 switch (type) { 305 switch (type) {
273 case Subrange::SOURCE: 306 case Subrange::SOURCE:
274 if (source.is_system_absolute()) 307 if (source.is_system_absolute())
275 return source.value(); 308 return source.value();
276 return RebaseSourceAbsolutePath(source.value(), 309 to_rebase = source.value();
277 settings->build_settings()->build_dir()); 310 break;
278 311
279 case Subrange::NAME_PART: 312 case Subrange::NAME_PART:
280 return FindFilenameNoExtension(&source.value()).as_string(); 313 return FindFilenameNoExtension(&source.value()).as_string();
281 314
282 case Subrange::FILE_PART: 315 case Subrange::FILE_PART:
283 return source.GetName(); 316 return source.GetName();
284 317
285 case Subrange::SOURCE_DIR: 318 case Subrange::SOURCE_DIR:
286 if (source.is_system_absolute()) 319 if (source.is_system_absolute())
287 return DirectoryWithNoLastSlash(source.GetDir()); 320 return DirectoryWithNoLastSlash(source.GetDir());
288 return RebaseSourceAbsolutePath( 321 to_rebase = DirectoryWithNoLastSlash(source.GetDir());
289 DirectoryWithNoLastSlash(source.GetDir()), 322 break;
290 settings->build_settings()->build_dir());
291 323
292 case Subrange::ROOT_RELATIVE_DIR: 324 case Subrange::ROOT_RELATIVE_DIR:
293 if (source.is_system_absolute()) 325 if (source.is_system_absolute())
294 return DirectoryWithNoLastSlash(source.GetDir()); 326 return DirectoryWithNoLastSlash(source.GetDir());
295 return RebaseSourceAbsolutePath( 327 return RebaseSourceAbsolutePath(
296 DirectoryWithNoLastSlash(source.GetDir()), SourceDir("//")); 328 DirectoryWithNoLastSlash(source.GetDir()), SourceDir("//"));
297 329
298 case Subrange::SOURCE_GEN_DIR: 330 case Subrange::SOURCE_GEN_DIR:
299 return RebaseSourceAbsolutePath( 331 to_rebase = DirectoryWithNoLastSlash(
300 DirectoryWithNoLastSlash( 332 GetGenDirForSourceDir(settings, source.GetDir()));
301 GetGenDirForSourceDir(settings, source.GetDir())), 333 break;
302 settings->build_settings()->build_dir());
303 334
304 case Subrange::SOURCE_OUT_DIR: 335 case Subrange::SOURCE_OUT_DIR:
305 return RebaseSourceAbsolutePath( 336 to_rebase = DirectoryWithNoLastSlash(
306 DirectoryWithNoLastSlash( 337 GetOutputDirForSourceDir(settings, source.GetDir()));
307 GetOutputDirForSourceDir(settings, source.GetDir())), 338 break;
308 settings->build_settings()->build_dir());
309 339
310 default: 340 default:
311 NOTREACHED(); 341 NOTREACHED();
342 return std::string();
312 } 343 }
313 return std::string(); 344
345 // If we get here, the result is a path that should be made relative or
346 // absolute according to the output_style. Other cases (just file name or
347 // extension extraction) will have been handled via early return above.
348 if (output_style == OUTPUT_ABSOLUTE)
349 return to_rebase;
350 return RebaseSourceAbsolutePath(to_rebase, relative_to);
314 } 351 }
315 352
316 void FileTemplate::ParseInput(const Value& value, Err* err) { 353 void FileTemplate::ParseInput(const Value& value, Err* err) {
317 switch (value.type()) { 354 switch (value.type()) {
318 case Value::STRING: 355 case Value::STRING:
319 ParseOneTemplateString(value.string_value()); 356 ParseOneTemplateString(value.string_value());
320 break; 357 break;
321 case Value::LIST: 358 case Value::LIST:
322 for (size_t i = 0; i < value.list_value().size(); i++) { 359 for (size_t i = 0; i < value.list_value().size(); i++) {
323 if (!value.list_value()[i].VerifyTypeIs(Value::STRING, err)) 360 if (!value.list_value()[i].VerifyTypeIs(Value::STRING, err))
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 // If it's not a match, treat it like a one-char literal (this will be 410 // If it's not a match, treat it like a one-char literal (this will be
374 // rare, so it's not worth the bother to add to the previous literal) so 411 // rare, so it's not worth the bother to add to the previous literal) so
375 // we can keep going. 412 // we can keep going.
376 t.container().push_back(Subrange(Subrange::LITERAL, "{")); 413 t.container().push_back(Subrange(Subrange::LITERAL, "{"));
377 cur = next + 1; 414 cur = next + 1;
378 } 415 }
379 416
380 #undef IF_MATCH_THEN_STORE 417 #undef IF_MATCH_THEN_STORE
381 } 418 }
382 } 419 }
OLDNEW
« no previous file with comments | « tools/gn/file_template.h ('k') | tools/gn/file_template_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698