OLD | NEW |
| (Empty) |
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/functions.h" | |
6 | |
7 #include <iostream> | |
8 | |
9 #include "base/strings/string_util.h" | |
10 #include "tools/gn/config.h" | |
11 #include "tools/gn/config_values_generator.h" | |
12 #include "tools/gn/err.h" | |
13 #include "tools/gn/input_file.h" | |
14 #include "tools/gn/item_tree.h" | |
15 #include "tools/gn/parse_tree.h" | |
16 #include "tools/gn/scheduler.h" | |
17 #include "tools/gn/scope.h" | |
18 #include "tools/gn/settings.h" | |
19 #include "tools/gn/target_manager.h" | |
20 #include "tools/gn/token.h" | |
21 #include "tools/gn/value.h" | |
22 | |
23 namespace { | |
24 | |
25 void FillNeedsBlockError(const FunctionCallNode* function, Err* err) { | |
26 *err = Err(function->function(), "This function call requires a block.", | |
27 "The block's \"{\" must be on the same line as the function " | |
28 "call's \")\"."); | |
29 } | |
30 | |
31 Value ExecuteAssert(const FunctionCallNode* function, | |
32 const std::vector<Value>& args, | |
33 Err* err) { | |
34 if (args.size() != 1) { | |
35 *err = Err(function->function(), "Wrong number of arguments.", | |
36 "assert() takes one argument, " | |
37 "were you expecting somethig else?"); | |
38 } else if (args[0].InterpretAsInt() == 0) { | |
39 *err = Err(function->function(), "Assertion failed."); | |
40 if (args[0].origin()) { | |
41 // If you do "assert(foo)" we'd ideally like to show you where foo was | |
42 // set, and in this case the origin of the args will tell us that. | |
43 // However, if you do "assert(foo && bar)" the source of the value will | |
44 // be the assert like, which isn't so helpful. | |
45 // | |
46 // So we try to see if the args are from the same line or not. This will | |
47 // break if you do "assert(\nfoo && bar)" and we may show the second line | |
48 // as the source, oh well. The way around this is to check to see if the | |
49 // origin node is inside our function call block. | |
50 Location origin_location = args[0].origin()->GetRange().begin(); | |
51 if (origin_location.file() != function->function().location().file() || | |
52 origin_location.line_number() != | |
53 function->function().location().line_number()) { | |
54 err->AppendSubErr(Err(args[0].origin()->GetRange(), "", | |
55 "This is where it was set.")); | |
56 } | |
57 } | |
58 } | |
59 return Value(); | |
60 } | |
61 | |
62 Value ExecuteConfig(Scope* scope, | |
63 const FunctionCallNode* function, | |
64 const std::vector<Value>& args, | |
65 Err* err) { | |
66 if (!EnsureSingleStringArg(function, args, err) || | |
67 !EnsureNotProcessingImport(function, scope, err)) | |
68 return Value(); | |
69 | |
70 Label label(MakeLabelForScope(scope, function, args[0].string_value())); | |
71 | |
72 if (g_scheduler->verbose_logging()) | |
73 g_scheduler->Log("Generating config", label.GetUserVisibleName(true)); | |
74 | |
75 // Create the empty config object. | |
76 ItemTree* tree = &scope->settings()->build_settings()->item_tree(); | |
77 Config* config = Config::GetConfig(scope->settings(), function->GetRange(), | |
78 label, NULL, err); | |
79 if (err->has_error()) | |
80 return Value(); | |
81 | |
82 // Fill it. | |
83 const SourceDir input_dir = SourceDirForFunctionCall(function); | |
84 ConfigValuesGenerator gen(&config->config_values(), scope, | |
85 function->function(), input_dir, err); | |
86 gen.Run(); | |
87 if (err->has_error()) | |
88 return Value(); | |
89 | |
90 // Mark as complete. | |
91 { | |
92 base::AutoLock lock(tree->lock()); | |
93 tree->MarkItemGeneratedLocked(label); | |
94 } | |
95 return Value(); | |
96 } | |
97 | |
98 Value ExecuteDeclareArgs(Scope* scope, | |
99 const FunctionCallNode* function, | |
100 const std::vector<Value>& args, | |
101 Err* err) { | |
102 // Only allow this to be called once. We use a variable in the current scope | |
103 // with a name the parser will reject if the user tried to type it. | |
104 const char did_declare_args_var[] = "@@declared_args"; | |
105 if (scope->GetValue(did_declare_args_var)) { | |
106 *err = Err(function->function(), "Duplicate call to declared_args."); | |
107 err->AppendSubErr( | |
108 Err(scope->GetValue(did_declare_args_var)->origin()->GetRange(), | |
109 "See the original call.")); | |
110 return Value(); | |
111 } | |
112 | |
113 // Find the root scope where the values will be set. | |
114 Scope* root = scope->mutable_containing(); | |
115 if (!root || root->containing() || !scope->IsProcessingBuildConfig()) { | |
116 *err = Err(function->function(), "declare_args called incorrectly." | |
117 "It must be called only from the build config script and in the " | |
118 "root scope."); | |
119 return Value(); | |
120 } | |
121 | |
122 // Take all variables set in the current scope as default values and put | |
123 // them in the parent scope. The values in the current scope are the defaults, | |
124 // then we apply the external args to this list. | |
125 Scope::KeyValueVector values; | |
126 scope->GetCurrentScopeValues(&values); | |
127 for (size_t i = 0; i < values.size(); i++) { | |
128 // TODO(brettw) actually import the arguments from the command line rather | |
129 // than only using the defaults. | |
130 root->SetValue(values[i].first, values[i].second, | |
131 values[i].second.origin()); | |
132 } | |
133 | |
134 scope->SetValue(did_declare_args_var, Value(function, 1), NULL); | |
135 return Value(); | |
136 } | |
137 | |
138 Value ExecuteImport(Scope* scope, | |
139 const FunctionCallNode* function, | |
140 const std::vector<Value>& args, | |
141 Err* err) { | |
142 if (!EnsureSingleStringArg(function, args, err) || | |
143 !EnsureNotProcessingImport(function, scope, err)) | |
144 return Value(); | |
145 | |
146 const SourceDir input_dir = SourceDirForFunctionCall(function); | |
147 SourceFile import_file = | |
148 input_dir.ResolveRelativeFile(args[0].string_value()); | |
149 scope->settings()->import_manager().DoImport(import_file, function, | |
150 scope, err); | |
151 return Value(); | |
152 } | |
153 | |
154 Value ExecuteTemplate(Scope* scope, | |
155 const FunctionCallNode* invocation, | |
156 const std::vector<Value>& args, | |
157 BlockNode* block, | |
158 const FunctionCallNode* rule, | |
159 Err* err) { | |
160 if (!EnsureNotProcessingImport(invocation, scope, err)) | |
161 return Value(); | |
162 Scope block_scope(scope); | |
163 if (!FillTargetBlockScope(scope, invocation, | |
164 invocation->function().value().data(), | |
165 block, args, &block_scope, err)) | |
166 return Value(); | |
167 | |
168 // Run the block for the rule invocation. | |
169 block->ExecuteBlockInScope(&block_scope, err); | |
170 if (err->has_error()) | |
171 return Value(); | |
172 | |
173 // Now run the rule itself with that block as the current scope. | |
174 rule->block()->ExecuteBlockInScope(&block_scope, err); | |
175 if (err->has_error()) | |
176 return Value(); | |
177 | |
178 return Value(); | |
179 } | |
180 | |
181 Value ExecuteSetDefaults(Scope* scope, | |
182 const FunctionCallNode* function, | |
183 const std::vector<Value>& args, | |
184 BlockNode* block, | |
185 Err* err) { | |
186 if (!EnsureSingleStringArg(function, args, err)) | |
187 return Value(); | |
188 const std::string& target_type(args[0].string_value()); | |
189 | |
190 // Ensure there aren't defaults already set. | |
191 if (scope->GetTargetDefaults(target_type)) { | |
192 *err = Err(function->function(), | |
193 "This target type defaults were already set."); | |
194 return Value(); | |
195 } | |
196 | |
197 // Execute the block in a new scope that has a parent of the containing | |
198 // scope. | |
199 Scope block_scope(scope); | |
200 if (!FillTargetBlockScope(scope, function, | |
201 function->function().value().data(), | |
202 block, args, &block_scope, err)) | |
203 return Value(); | |
204 | |
205 // Run the block for the rule invocation. | |
206 block->ExecuteBlockInScope(&block_scope, err); | |
207 if (err->has_error()) | |
208 return Value(); | |
209 | |
210 // Now copy the values set on the scope we made into the free-floating one | |
211 // (with no containing scope) used to hold the target defaults. | |
212 Scope* dest = scope->MakeTargetDefaults(target_type); | |
213 block_scope.NonRecursiveMergeTo(dest, function, "<SHOULD NOT FAIL>", err); | |
214 return Value(); | |
215 } | |
216 | |
217 Value ExecuteSetSourcesAssignmentFilter(Scope* scope, | |
218 const FunctionCallNode* function, | |
219 const std::vector<Value>& args, | |
220 Err* err) { | |
221 if (args.size() != 1) { | |
222 *err = Err(function, "set_sources_assignment_filter takes one argument."); | |
223 } else { | |
224 scoped_ptr<PatternList> f(new PatternList); | |
225 f->SetFromValue(args[0], err); | |
226 if (!err->has_error()) | |
227 scope->set_sources_assignment_filter(f.Pass()); | |
228 } | |
229 return Value(); | |
230 } | |
231 | |
232 // void print(...) | |
233 // prints all arguments to the console separated by spaces. | |
234 Value ExecutePrint(const std::vector<Value>& args, Err* err) { | |
235 for (size_t i = 0; i < args.size(); i++) { | |
236 if (i != 0) | |
237 std::cout << " "; | |
238 std::cout << args[i].ToString(); | |
239 } | |
240 std::cout << std::endl; | |
241 return Value(); | |
242 } | |
243 | |
244 } // namespace | |
245 | |
246 // ---------------------------------------------------------------------------- | |
247 | |
248 namespace functions { | |
249 | |
250 const char kAssert[] = "assert"; | |
251 const char kComponent[] = "component"; | |
252 const char kConfig[] = "config"; | |
253 const char kCopy[] = "copy"; | |
254 const char kCustom[] = "custom"; | |
255 const char kDeclareArgs[] = "declare_args"; | |
256 const char kExecScript[] = "exec_script"; | |
257 const char kExecutable[] = "executable"; | |
258 const char kGroup[] = "group"; | |
259 const char kImport[] = "import"; | |
260 const char kPrint[] = "print"; | |
261 const char kProcessFileTemplate[] = "process_file_template"; | |
262 const char kReadFile[] = "read_file"; | |
263 const char kSetDefaults[] = "set_defaults"; | |
264 const char kSetDefaultToolchain[] = "set_default_toolchain"; | |
265 const char kSetSourcesAssignmentFilter[] = "set_sources_assignment_filter"; | |
266 const char kSharedLibrary[] = "shared_library"; | |
267 const char kStaticLibrary[] = "static_library"; | |
268 const char kTemplate[] = "template"; | |
269 const char kTool[] = "tool"; | |
270 const char kToolchain[] = "toolchain"; | |
271 const char kTest[] = "test"; | |
272 const char kWriteFile[] = "write_file"; | |
273 | |
274 } // namespace functions | |
275 | |
276 // ---------------------------------------------------------------------------- | |
277 | |
278 bool EnsureNotProcessingImport(const ParseNode* node, | |
279 const Scope* scope, | |
280 Err* err) { | |
281 if (scope->IsProcessingImport()) { | |
282 *err = Err(node, "Not valid from an import.", | |
283 "We need to talk about this thing you are doing here. Doing this\n" | |
284 "kind of thing from an imported file makes me feel like you are\n" | |
285 "abusing me. Imports are for defining defaults, variables, and rules.\n" | |
286 "The appropriate place for this kind of thing is really in a normal\n" | |
287 "BUILD file."); | |
288 return false; | |
289 } | |
290 return true; | |
291 } | |
292 | |
293 bool EnsureNotProcessingBuildConfig(const ParseNode* node, | |
294 const Scope* scope, | |
295 Err* err) { | |
296 if (scope->IsProcessingBuildConfig()) { | |
297 *err = Err(node, "Not valid from the build config.", | |
298 "You can't do this kind of thing from the build config script, " | |
299 "silly!\nPut it in a regular BUILD file."); | |
300 return false; | |
301 } | |
302 return true; | |
303 } | |
304 | |
305 bool FillTargetBlockScope(const Scope* scope, | |
306 const FunctionCallNode* function, | |
307 const char* target_type, | |
308 const BlockNode* block, | |
309 const std::vector<Value>& args, | |
310 Scope* block_scope, | |
311 Err* err) { | |
312 if (!block) { | |
313 FillNeedsBlockError(function, err); | |
314 return false; | |
315 } | |
316 | |
317 // Copy the target defaults, if any, into the scope we're going to execute | |
318 // the block in. | |
319 const Scope* default_scope = scope->GetTargetDefaults(target_type); | |
320 if (default_scope) { | |
321 if (!default_scope->NonRecursiveMergeTo(block_scope, function, | |
322 "target defaults", err)) | |
323 return false; | |
324 } | |
325 | |
326 // The name is the single argument to the target function. | |
327 if (!EnsureSingleStringArg(function, args, err)) | |
328 return false; | |
329 | |
330 // Set the target name variable to the current target, and mark it used | |
331 // because we don't want to issue an error if the script ignores it. | |
332 const base::StringPiece target_name("target_name"); | |
333 block_scope->SetValue(target_name, Value(function, args[0].string_value()), | |
334 function); | |
335 block_scope->MarkUsed(target_name); | |
336 return true; | |
337 } | |
338 | |
339 bool EnsureSingleStringArg(const FunctionCallNode* function, | |
340 const std::vector<Value>& args, | |
341 Err* err) { | |
342 if (args.size() != 1) { | |
343 *err = Err(function->function(), "Incorrect arguments.", | |
344 "This function requires a single string argument."); | |
345 return false; | |
346 } | |
347 return args[0].VerifyTypeIs(Value::STRING, err); | |
348 } | |
349 | |
350 const SourceDir& SourceDirForFunctionCall(const FunctionCallNode* function) { | |
351 return function->function().location().file()->dir(); | |
352 } | |
353 | |
354 const Label& ToolchainLabelForScope(const Scope* scope) { | |
355 return scope->settings()->toolchain()->label(); | |
356 } | |
357 | |
358 Label MakeLabelForScope(const Scope* scope, | |
359 const FunctionCallNode* function, | |
360 const std::string& name) { | |
361 const SourceDir& input_dir = SourceDirForFunctionCall(function); | |
362 const Label& toolchain_label = ToolchainLabelForScope(scope); | |
363 return Label(input_dir, name, toolchain_label.dir(), toolchain_label.name()); | |
364 } | |
365 | |
366 Value ExecuteFunction(Scope* scope, | |
367 const FunctionCallNode* function, | |
368 const std::vector<Value>& args, | |
369 BlockNode* block, | |
370 Err* err) { | |
371 const Token& name = function->function(); | |
372 if (block) { | |
373 // These target generators need to execute the block themselves. | |
374 if (name.IsIdentifierEqualTo(functions::kComponent)) | |
375 return ExecuteComponent(scope, function, args, block, err); | |
376 if (name.IsIdentifierEqualTo(functions::kCustom)) | |
377 return ExecuteCustom(scope, function, args, block, err); | |
378 if (name.IsIdentifierEqualTo(functions::kExecutable)) | |
379 return ExecuteExecutable(scope, function, args, block, err); | |
380 if (name.IsIdentifierEqualTo(functions::kSetDefaults)) | |
381 return ExecuteSetDefaults(scope, function, args, block, err); | |
382 if (name.IsIdentifierEqualTo(functions::kSharedLibrary)) | |
383 return ExecuteSharedLibrary(scope, function, args, block, err); | |
384 if (name.IsIdentifierEqualTo(functions::kStaticLibrary)) | |
385 return ExecuteStaticLibrary(scope, function, args, block, err); | |
386 if (name.IsIdentifierEqualTo(functions::kGroup)) | |
387 return ExecuteGroup(scope, function, args, block, err); | |
388 if (name.IsIdentifierEqualTo(functions::kTest)) | |
389 return ExecuteExecutable(scope, function, args, block, err); | |
390 if (name.IsIdentifierEqualTo(functions::kTemplate)) | |
391 return ExecuteTemplate(scope, function, args, block, err); | |
392 if (name.IsIdentifierEqualTo(functions::kTool)) | |
393 return ExecuteTool(scope, function, args, block, err); | |
394 if (name.IsIdentifierEqualTo(functions::kToolchain)) | |
395 return ExecuteToolchain(scope, function, args, block, err); | |
396 | |
397 const FunctionCallNode* rule = | |
398 scope->GetTemplate(function->function().value().as_string()); | |
399 if (rule) | |
400 return ExecuteTemplate(scope, function, args, block, rule, err); | |
401 | |
402 // FIXME(brettw) This is not right, what if you specify a function that | |
403 // doesn't take a block but specify one?!?!? | |
404 | |
405 // The rest of the functions can take a pre-executed block for simplicity. | |
406 Scope block_scope(scope); | |
407 block->ExecuteBlockInScope(&block_scope, err); | |
408 if (err->has_error()) | |
409 return Value(); | |
410 | |
411 if (name.IsIdentifierEqualTo(functions::kConfig)) | |
412 return ExecuteConfig(&block_scope, function, args, err); | |
413 if (name.IsIdentifierEqualTo(functions::kCopy)) | |
414 return ExecuteCopy(&block_scope, function, args, err); | |
415 if (name.IsIdentifierEqualTo(functions::kDeclareArgs)) | |
416 return ExecuteDeclareArgs(&block_scope, function, args, err); | |
417 | |
418 *err = Err(name, "Unknown function."); | |
419 return Value(); | |
420 } | |
421 | |
422 if (name.IsIdentifierEqualTo(functions::kAssert)) | |
423 return ExecuteAssert(function, args, err); | |
424 if (name.IsIdentifierEqualTo(functions::kExecScript)) | |
425 return ExecuteExecScript(scope, function, args, err); | |
426 if (name.IsIdentifierEqualTo(functions::kImport)) | |
427 return ExecuteImport(scope, function, args, err); | |
428 if (name.IsIdentifierEqualTo(functions::kPrint)) | |
429 return ExecutePrint(args, err); | |
430 if (name.IsIdentifierEqualTo(functions::kProcessFileTemplate)) | |
431 return ExecuteProcessFileTemplate(scope, function, args, err); | |
432 if (name.IsIdentifierEqualTo(functions::kReadFile)) | |
433 return ExecuteReadFile(scope, function, args, err); | |
434 if (name.IsIdentifierEqualTo(functions::kSetDefaultToolchain)) | |
435 return ExecuteSetDefaultToolchain(scope, function, args, err); | |
436 if (name.IsIdentifierEqualTo(functions::kSetSourcesAssignmentFilter)) | |
437 return ExecuteSetSourcesAssignmentFilter(scope, function, args, err); | |
438 if (name.IsIdentifierEqualTo(functions::kWriteFile)) | |
439 return ExecuteWriteFile(scope, function, args, err); | |
440 | |
441 *err = Err(function, "Unknown function."); | |
442 return Value(); | |
443 } | |
OLD | NEW |