OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |