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

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

Issue 21114002: Add initial prototype for the GN meta-buildsystem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add owners and readme Created 7 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/functions.h ('k') | tools/gn/functions_target.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « tools/gn/functions.h ('k') | tools/gn/functions_target.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698