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

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

Issue 334333005: Add directory extraction to GN path handling. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge to new file template function Created 6 years, 6 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"
11 #include "tools/gn/filesystem_utils.h" 11 #include "tools/gn/filesystem_utils.h"
12 #include "tools/gn/string_utils.h" 12 #include "tools/gn/string_utils.h"
13 #include "tools/gn/target.h" 13 #include "tools/gn/target.h"
14 14
15 const char FileTemplate::kSource[] = "{{source}}"; 15 const char FileTemplate::kSource[] = "{{source}}";
16 const char FileTemplate::kSourceNamePart[] = "{{source_name_part}}"; 16 const char FileTemplate::kSourceNamePart[] = "{{source_name_part}}";
17 const char FileTemplate::kSourceFilePart[] = "{{source_file_part}}"; 17 const char FileTemplate::kSourceFilePart[] = "{{source_file_part}}";
18 const char FileTemplate::kSourceDir[] = "{{source_dir}}";
19 const char FileTemplate::kRootRelDir[] = "{{source_root_relative_dir}}";
20 const char FileTemplate::kSourceGenDir[] = "{{source_gen_dir}}";
21 const char FileTemplate::kSourceOutDir[] = "{{source_out_dir}}";
18 22
19 const char kSourceExpansion_Help[] = 23 const char kSourceExpansion_Help[] =
20 "How Source Expansion Works\n" 24 "How Source Expansion Works\n"
21 "\n" 25 "\n"
22 " Source expansion is used for the action_foreach and copy target types\n" 26 " Source expansion is used for the action_foreach and copy target types\n"
23 " to map source file names to output file names or arguments.\n" 27 " to map source file names to output file names or arguments.\n"
24 "\n" 28 "\n"
25 " To perform source expansion in the outputs, GN maps every entry in the\n" 29 " To perform source expansion in the outputs, GN maps every entry in the\n"
26 " sources to every entry in the outputs list, producing the cross\n" 30 " sources to every entry in the outputs list, producing the cross\n"
27 " product of all combinations, expanding placeholders (see below).\n" 31 " product of all combinations, expanding placeholders (see below).\n"
28 "\n" 32 "\n"
29 " Source expansion in the args works similarly, but performing the\n" 33 " Source expansion in the args works similarly, but performing the\n"
30 " placeholder substitution produces a different set of arguments for\n" 34 " placeholder substitution produces a different set of arguments for\n"
31 " each invocation of the script.\n" 35 " each invocation of the script.\n"
32 "\n" 36 "\n"
33 " 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"
34 " 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"
35 " sources.\n" 39 " sources.\n"
36 "\n" 40 "\n"
37 " 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"
38 " this is applied.\n" 42 " this is applied.\n"
39 "\n" 43 "\n"
40 "Placeholders\n" 44 "Placeholders\n"
41 "\n" 45 "\n"
42 " {{source}}\n" 46 " {{source}}\n"
43 " The name of the source file relative to the root build output\n" 47 " The name of the source file relative to the root build output\n"
44 " directory (which is the current directory when running compilers\n" 48 " directory (which is the current directory when running compilers\n"
45 " and scripts). This will generally be used for specifying inputs\n" 49 " and scripts). This will generally be used for specifying inputs\n"
46 " to a script in the \"args\" variable.\n" 50 " to a script in the \"args\" variable.\n"
51 " \"//foo/bar/baz.txt\" => \"../../foo/bar/baz.txt\"\n"
47 "\n" 52 "\n"
48 " {{source_file_part}}\n" 53 " {{source_file_part}}\n"
49 " The file part of the source including the extension. For the\n" 54 " The file part of the source including the extension.\n"
50 " source \"foo/bar.txt\" the source file part will be \"bar.txt\".\n" 55 " \"//foo/bar/baz.txt\" => \"baz.txt\"\n"
51 "\n" 56 "\n"
52 " {{source_name_part}}\n" 57 " {{source_name_part}}\n"
53 " The filename part of the source file with no directory or\n" 58 " The filename part of the source file with no directory or\n"
54 " extension. This will generally be used for specifying a\n" 59 " extension. This will generally be used for specifying a\n"
55 " transformation from a soruce file to a destination file with the\n" 60 " transformation from a soruce file to a destination file with the\n"
56 " same name but different extension. For the source \"foo/bar.txt\"\n" 61 " same name but different extension.\n"
57 " the source name part will be \"bar\".\n" 62 " \"//foo/bar/baz.txt\" => \"baz\"\n"
63 "\n"
64 " {{source_dir}}\n"
65 " The directory containing the source file, relative to the build\n"
66 " directory, with no trailing slash.\n"
67 " \"//foo/bar/baz.txt\" => \"../../foo/bar\"\n"
68 "\n"
69 " {{source_root_relative_dir}}\n"
70 " 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"
72 " system-absolute, (beginning in a single slash) this will just\n"
73 " return the path with no trailing slash.\n"
74 " \"//foo/bar/baz.txt\" => \"foo/bar\"\n"
75 "\n"
76 " {{source_gen_dir}}\n"
77 " The generated file directory corresponding to the source file's\n"
78 " path, relative to the build directory. This will be different than\n"
79 " the target's generated file directory if the source file is in a\n"
80 " different directory than the build.gn file. If the input path is\n"
81 " system absolute, this will return the root generated file\n"
82 " directory."
83 " \"//foo/bar/baz.txt\" => \"gen/foo/bar\"\n"
84 "\n"
85 " {{source_out_dir}}\n"
86 " The object file directory corresponding to the source file's\n"
87 " 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"
89 " directory than the build.gn file. if the input path is system\n"
90 " absolute, this will return the root generated file directory.\n"
91 " \"//foo/bar/baz.txt\" => \"obj/foo/bar\"\n"
58 "\n" 92 "\n"
59 "Examples\n" 93 "Examples\n"
60 "\n" 94 "\n"
61 " Non-varying outputs:\n" 95 " Non-varying outputs:\n"
62 " action(\"hardcoded_outputs\") {\n" 96 " action(\"hardcoded_outputs\") {\n"
63 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" 97 " sources = [ \"input1.idl\", \"input2.idl\" ]\n"
64 " outputs = [ \"$target_out_dir/output1.dat\",\n" 98 " outputs = [ \"$target_out_dir/output1.dat\",\n"
65 " \"$target_out_dir/output2.dat\" ]\n" 99 " \"$target_out_dir/output2.dat\" ]\n"
66 " }\n" 100 " }\n"
67 " The outputs in this case will be the two literal files given.\n" 101 " The outputs in this case will be the two literal files given.\n"
68 "\n" 102 "\n"
69 " Varying outputs:\n" 103 " Varying outputs:\n"
70 " action_foreach(\"varying_outputs\") {\n" 104 " action_foreach(\"varying_outputs\") {\n"
71 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" 105 " sources = [ \"input1.idl\", \"input2.idl\" ]\n"
72 " outputs = [ \"$target_out_dir/{{source_name_part}}.h\",\n" 106 " outputs = [ \"$target_out_dir/{{source_name_part}}.h\",\n"
73 " \"$target_out_dir/{{source_name_part}}.cc\" ]\n" 107 " \"$target_out_dir/{{source_name_part}}.cc\" ]\n"
74 " }\n" 108 " }\n"
75 " Performing source expansion will result in the following output names:\n" 109 " Performing source expansion will result in the following output names:\n"
76 " //out/Debug/obj/mydirectory/input1.h\n" 110 " //out/Debug/obj/mydirectory/input1.h\n"
77 " //out/Debug/obj/mydirectory/input1.cc\n" 111 " //out/Debug/obj/mydirectory/input1.cc\n"
78 " //out/Debug/obj/mydirectory/input2.h\n" 112 " //out/Debug/obj/mydirectory/input2.h\n"
79 " //out/Debug/obj/mydirectory/input2.cc\n"; 113 " //out/Debug/obj/mydirectory/input2.cc\n";
80 114
81 FileTemplate::FileTemplate(const Value& t, Err* err) 115 FileTemplate::FileTemplate(const Settings* settings, const Value& t, Err* err)
82 : has_substitutions_(false) { 116 : settings_(settings),
117 has_substitutions_(false) {
83 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); 118 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
84 ParseInput(t, err); 119 ParseInput(t, err);
85 } 120 }
86 121
87 FileTemplate::FileTemplate(const std::vector<std::string>& t) 122 FileTemplate::FileTemplate(const Settings* settings,
88 : has_substitutions_(false) { 123 const std::vector<std::string>& t)
124 : settings_(settings),
125 has_substitutions_(false) {
89 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); 126 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
90 for (size_t i = 0; i < t.size(); i++) 127 for (size_t i = 0; i < t.size(); i++)
91 ParseOneTemplateString(t[i]); 128 ParseOneTemplateString(t[i]);
92 } 129 }
93 130
94 FileTemplate::FileTemplate(const std::vector<SourceFile>& t) 131 FileTemplate::FileTemplate(const Settings* settings,
95 : has_substitutions_(false) { 132 const std::vector<SourceFile>& t)
133 : settings_(settings),
134 has_substitutions_(false) {
96 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); 135 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false);
97 for (size_t i = 0; i < t.size(); i++) 136 for (size_t i = 0; i < t.size(); i++)
98 ParseOneTemplateString(t[i].value()); 137 ParseOneTemplateString(t[i].value());
99 } 138 }
100 139
101 FileTemplate::~FileTemplate() { 140 FileTemplate::~FileTemplate() {
102 } 141 }
103 142
104 // static 143 // static
105 FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) { 144 FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) {
106 const Target::FileList& outputs = target->action_values().outputs(); 145 const Target::FileList& outputs = target->action_values().outputs();
107 std::vector<std::string> output_template_args; 146 std::vector<std::string> output_template_args;
108 for (size_t i = 0; i < outputs.size(); i++) 147 for (size_t i = 0; i < outputs.size(); i++)
109 output_template_args.push_back(outputs[i].value()); 148 output_template_args.push_back(outputs[i].value());
110 return FileTemplate(output_template_args); 149 return FileTemplate(target->settings(), output_template_args);
111 } 150 }
112 151
113 bool FileTemplate::IsTypeUsed(Subrange::Type type) const { 152 bool FileTemplate::IsTypeUsed(Subrange::Type type) const {
114 DCHECK(type > Subrange::LITERAL && type < Subrange::NUM_TYPES); 153 DCHECK(type > Subrange::LITERAL && type < Subrange::NUM_TYPES);
115 return types_required_[type]; 154 return types_required_[type];
116 } 155 }
117 156
118 void FileTemplate::Apply(const Value& sources, 157 void FileTemplate::Apply(const SourceFile& source,
119 const ParseNode* origin, 158 std::vector<std::string>* output) const {
120 std::vector<Value>* dest,
121 Err* err) const {
122 if (!sources.VerifyTypeIs(Value::LIST, err))
123 return;
124 dest->reserve(sources.list_value().size() * templates_.container().size());
125
126 // Temporary holding place, allocate outside to re-use- buffer.
127 std::vector<std::string> string_output;
128
129 const std::vector<Value>& sources_list = sources.list_value();
130 for (size_t i = 0; i < sources_list.size(); i++) {
131 string_output.clear();
132 if (!sources_list[i].VerifyTypeIs(Value::STRING, err))
133 return;
134
135 ApplyString(sources_list[i].string_value(), &string_output);
136 for (size_t out_i = 0; out_i < string_output.size(); out_i++)
137 dest->push_back(Value(origin, string_output[out_i]));
138 }
139 }
140
141 void FileTemplate::ApplyString(const std::string& str,
142 std::vector<std::string>* output) const {
143 // Compute all substitutions needed so we can just do substitutions below. 159 // Compute all substitutions needed so we can just do substitutions below.
144 // We skip the LITERAL one since that varies each time. 160 // We skip the LITERAL one since that varies each time.
145 std::string subst[Subrange::NUM_TYPES]; 161 std::string subst[Subrange::NUM_TYPES];
146 for (int i = 1; i < Subrange::NUM_TYPES; i++) { 162 for (int i = 1; i < Subrange::NUM_TYPES; i++) {
147 if (types_required_[i]) 163 if (types_required_[i]) {
148 subst[i] = GetSubstitution(str, static_cast<Subrange::Type>(i)); 164 subst[i] =
165 GetSubstitution(settings_, source, static_cast<Subrange::Type>(i));
166 }
149 } 167 }
150 168
151 size_t first_output_index = output->size(); 169 size_t first_output_index = output->size();
152 output->resize(output->size() + templates_.container().size()); 170 output->resize(output->size() + templates_.container().size());
153 for (size_t template_i = 0; 171 for (size_t template_i = 0;
154 template_i < templates_.container().size(); template_i++) { 172 template_i < templates_.container().size(); template_i++) {
155 const Template& t = templates_[template_i]; 173 const Template& t = templates_[template_i];
156 std::string& cur_output = (*output)[first_output_index + template_i]; 174 std::string& cur_output = (*output)[first_output_index + template_i];
157 for (size_t subrange_i = 0; subrange_i < t.container().size(); 175 for (size_t subrange_i = 0; subrange_i < t.container().size();
158 subrange_i++) { 176 subrange_i++) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 // argument. 220 // argument.
203 out << '"' << item_str << '"'; 221 out << '"' << item_str << '"';
204 } else { 222 } else {
205 out << item_str; 223 out << item_str;
206 } 224 }
207 } 225 }
208 } 226 }
209 227
210 void FileTemplate::WriteNinjaVariablesForSubstitution( 228 void FileTemplate::WriteNinjaVariablesForSubstitution(
211 std::ostream& out, 229 std::ostream& out,
212 const std::string& source, 230 const Settings* settings,
231 const SourceFile& source,
213 const EscapeOptions& escape_options) const { 232 const EscapeOptions& escape_options) const {
214 for (int i = 1; i < Subrange::NUM_TYPES; i++) { 233 for (int i = 1; i < Subrange::NUM_TYPES; i++) {
215 if (types_required_[i]) { 234 if (types_required_[i]) {
216 Subrange::Type type = static_cast<Subrange::Type>(i); 235 Subrange::Type type = static_cast<Subrange::Type>(i);
217 out << " " << GetNinjaVariableNameForType(type) << " = "; 236 out << " " << GetNinjaVariableNameForType(type) << " = ";
218 EscapeStringToStream(out, GetSubstitution(source, type), escape_options); 237 EscapeStringToStream(out, GetSubstitution(settings, source, type),
238 escape_options);
219 out << std::endl; 239 out << std::endl;
220 } 240 }
221 } 241 }
222 } 242 }
223 243
224 // static 244 // static
225 const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) { 245 const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) {
226 switch (type) { 246 switch (type) {
227 case Subrange::SOURCE: 247 case Subrange::SOURCE:
228 return "source"; 248 return "source";
229 case Subrange::NAME_PART: 249 case Subrange::NAME_PART:
230 return "source_name_part"; 250 return "source_name_part";
231 case Subrange::FILE_PART: 251 case Subrange::FILE_PART:
232 return "source_file_part"; 252 return "source_file_part";
253 case Subrange::SOURCE_DIR:
254 return "source_dir";
255 case Subrange::ROOT_RELATIVE_DIR:
256 return "source_root_rel_dir";
257 case Subrange::SOURCE_GEN_DIR:
258 return "source_gen_dir";
259 case Subrange::SOURCE_OUT_DIR:
260 return "source_out_dir";
261
233 default: 262 default:
234 NOTREACHED(); 263 NOTREACHED();
235 } 264 }
236 return ""; 265 return "";
237 } 266 }
238 267
239 // static 268 // static
240 std::string FileTemplate::GetSubstitution(const std::string& source, 269 std::string FileTemplate::GetSubstitution(const Settings* settings,
270 const SourceFile& source,
241 Subrange::Type type) { 271 Subrange::Type type) {
242 switch (type) { 272 switch (type) {
243 case Subrange::SOURCE: 273 case Subrange::SOURCE:
244 return source; 274 if (source.is_system_absolute())
275 return source.value();
276 return RebaseSourceAbsolutePath(source.value(),
277 settings->build_settings()->build_dir());
278
245 case Subrange::NAME_PART: 279 case Subrange::NAME_PART:
246 return FindFilenameNoExtension(&source).as_string(); 280 return FindFilenameNoExtension(&source.value()).as_string();
281
247 case Subrange::FILE_PART: 282 case Subrange::FILE_PART:
248 return FindFilename(&source).as_string(); 283 return source.GetName();
284
285 case Subrange::SOURCE_DIR:
286 if (source.is_system_absolute())
287 return DirectoryWithNoLastSlash(source.GetDir());
288 return RebaseSourceAbsolutePath(
289 DirectoryWithNoLastSlash(source.GetDir()),
290 settings->build_settings()->build_dir());
291
292 case Subrange::ROOT_RELATIVE_DIR:
293 if (source.is_system_absolute())
294 return DirectoryWithNoLastSlash(source.GetDir());
295 return RebaseSourceAbsolutePath(
296 DirectoryWithNoLastSlash(source.GetDir()), SourceDir("//"));
297
298 case Subrange::SOURCE_GEN_DIR:
299 return RebaseSourceAbsolutePath(
300 DirectoryWithNoLastSlash(
301 GetGenDirForSourceDir(settings, source.GetDir())),
302 settings->build_settings()->build_dir());
303
304 case Subrange::SOURCE_OUT_DIR:
305 return RebaseSourceAbsolutePath(
306 DirectoryWithNoLastSlash(
307 GetOutputDirForSourceDir(settings, source.GetDir())),
308 settings->build_settings()->build_dir());
309
249 default: 310 default:
250 NOTREACHED(); 311 NOTREACHED();
251 } 312 }
252 return std::string(); 313 return std::string();
253 } 314 }
254 315
255 void FileTemplate::ParseInput(const Value& value, Err* err) { 316 void FileTemplate::ParseInput(const Value& value, Err* err) {
256 switch (value.type()) { 317 switch (value.type()) {
257 case Value::STRING: 318 case Value::STRING:
258 ParseOneTemplateString(value.string_value()); 319 ParseOneTemplateString(value.string_value());
(...skipping 22 matching lines...) Expand all
281 // Pick up everything from the previous spot to here as a literal. 342 // Pick up everything from the previous spot to here as a literal.
282 if (next == std::string::npos) { 343 if (next == std::string::npos) {
283 if (cur != str.size()) 344 if (cur != str.size())
284 t.container().push_back(Subrange(Subrange::LITERAL, str.substr(cur))); 345 t.container().push_back(Subrange(Subrange::LITERAL, str.substr(cur)));
285 break; 346 break;
286 } else if (next > cur) { 347 } else if (next > cur) {
287 t.container().push_back( 348 t.container().push_back(
288 Subrange(Subrange::LITERAL, str.substr(cur, next - cur))); 349 Subrange(Subrange::LITERAL, str.substr(cur, next - cur)));
289 } 350 }
290 351
352 // Given the name of the string constant and enum for a template parameter,
353 // checks for it and stores it. Writing this as a function requires passing
354 // the entire state of this function as arguments, so this actually ends
355 // up being more clear.
356 #define IF_MATCH_THEN_STORE(const_name, enum_name) \
357 if (str.compare(next, arraysize(const_name) - 1, const_name) == 0) { \
358 t.container().push_back(Subrange(Subrange::enum_name)); \
359 types_required_[Subrange::enum_name] = true; \
360 has_substitutions_ = true; \
361 cur = next + arraysize(const_name) - 1; \
362 }
363
291 // Decode the template param. 364 // Decode the template param.
292 if (str.compare(next, arraysize(kSource) - 1, kSource) == 0) { 365 IF_MATCH_THEN_STORE(kSource, SOURCE)
293 t.container().push_back(Subrange(Subrange::SOURCE)); 366 else IF_MATCH_THEN_STORE(kSourceNamePart, NAME_PART)
294 types_required_[Subrange::SOURCE] = true; 367 else IF_MATCH_THEN_STORE(kSourceFilePart, FILE_PART)
295 has_substitutions_ = true; 368 else IF_MATCH_THEN_STORE(kSourceDir, SOURCE_DIR)
296 cur = next + arraysize(kSource) - 1; 369 else IF_MATCH_THEN_STORE(kRootRelDir, ROOT_RELATIVE_DIR)
297 } else if (str.compare(next, arraysize(kSourceNamePart) - 1, 370 else IF_MATCH_THEN_STORE(kSourceGenDir, SOURCE_GEN_DIR)
298 kSourceNamePart) == 0) { 371 else IF_MATCH_THEN_STORE(kSourceOutDir, SOURCE_OUT_DIR)
299 t.container().push_back(Subrange(Subrange::NAME_PART)); 372 else {
300 types_required_[Subrange::NAME_PART] = true;
301 has_substitutions_ = true;
302 cur = next + arraysize(kSourceNamePart) - 1;
303 } else if (str.compare(next, arraysize(kSourceFilePart) - 1,
304 kSourceFilePart) == 0) {
305 t.container().push_back(Subrange(Subrange::FILE_PART));
306 types_required_[Subrange::FILE_PART] = true;
307 has_substitutions_ = true;
308 cur = next + arraysize(kSourceFilePart) - 1;
309 } else {
310 // If it's not a match, treat it like a one-char literal (this will be 373 // If it's not a match, treat it like a one-char literal (this will be
311 // rare, so it's not worth the bother to add to the previous literal) so 374 // rare, so it's not worth the bother to add to the previous literal) so
312 // we can keep going. 375 // we can keep going.
313 t.container().push_back(Subrange(Subrange::LITERAL, "{")); 376 t.container().push_back(Subrange(Subrange::LITERAL, "{"));
314 cur = next + 1; 377 cur = next + 1;
315 } 378 }
379
380 #undef IF_MATCH_THEN_STORE
316 } 381 }
317 } 382 }
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