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 "tools/gn/config_values_generator.h"
8 #include "tools/gn/err.h"
9 #include "tools/gn/parse_tree.h"
10 #include "tools/gn/scope.h"
11 #include "tools/gn/target_generator.h"
12 #include "tools/gn/value.h"
13 #include "tools/gn/variables.h"
14
15 #define DEPENDENT_CONFIG_VARS \
16 " Dependent configs: all_dependent_configs, direct_dependent_configs\n"
17 #define DEPS_VARS \
18 " Deps: data, datadeps, deps, forward_dependent_configs_from, hard_dep\n"
19 #define GENERAL_TARGET_VARS \
20 " General: configs, inputs, sources\n"
21
22 namespace functions {
23
24 namespace {
25
ExecuteGenericTarget(const char * target_type,Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)26 Value ExecuteGenericTarget(const char* target_type,
27 Scope* scope,
28 const FunctionCallNode* function,
29 const std::vector<Value>& args,
30 BlockNode* block,
31 Err* err) {
32 if (!EnsureNotProcessingImport(function, scope, err) ||
33 !EnsureNotProcessingBuildConfig(function, scope, err))
34 return Value();
35 Scope block_scope(scope);
36 if (!FillTargetBlockScope(scope, function, target_type, block,
37 args, &block_scope, err))
38 return Value();
39
40 block->ExecuteBlockInScope(&block_scope, err);
41 if (err->has_error())
42 return Value();
43
44 TargetGenerator::GenerateTarget(&block_scope, function, args,
45 target_type, err);
46 if (err->has_error())
47 return Value();
48
49 block_scope.CheckForUnusedVars(err);
50 return Value();
51 }
52
53 } // namespace
54
55 // action ----------------------------------------------------------------------
56
57 // Common help paragraph on script runtime execution directories.
58 #define SCRIPT_EXECUTION_CONTEXT \
59 " The script will be executed with the given arguments with the current\n"\
60 " directory being that of the root build directory. If you pass files\n"\
61 " to your script, see \"gn help rebase_path\" for how to convert\n" \
62 " file names to be relative to the build directory (file names in the\n" \
63 " sources, outputs, and inputs will be all treated as relative to the\n" \
64 " current build file and converted as needed automatically).\n"
65
66 // Common help paragraph on script output directories.
67 #define SCRIPT_EXECUTION_OUTPUTS \
68 " All output files must be inside the output directory of the build.\n" \
69 " You would generally use |$target_out_dir| or |$target_gen_dir| to\n" \
70 " reference the output or generated intermediate file directories,\n" \
71 " respectively.\n"
72
73 #define ACTION_DEPS \
74 " The \"deps\" for an action will always be completed before any part\n" \
75 " of the action is run so it can depend on the output of previous\n" \
76 " steps. The \"datadeps\" will be built if the action is built, but\n" \
77 " may not have completed before all steps of the action are started.\n" \
78 " This can give additional parallelism in the build for runtime-only\n" \
79 " dependencies.\n"
80
81 const char kAction[] = "action";
82 const char kAction_HelpShort[] =
83 "action: Declare a target that runs a script a single time.";
84 const char kAction_Help[] =
85 "action: Declare a target that runs a script a single time.\n"
86 "\n"
87 " This target type allows you to run a script a single time to produce\n"
88 " or more output files. If you want to run a script once for each of a\n"
89 " set of input files, see \"gn help action_foreach\".\n"
90 "\n"
91 "Inputs\n"
92 "\n"
93 " In an action the \"sources\" and \"inputs\" are treated the same:\n"
94 " they're both input dependencies on script execution with no special\n"
95 " handling. If you want to pass the sources to your script, you must do\n"
96 " so explicitly by including them in the \"args\". Note also that this\n"
97 " means there is no special handling of paths since GN doesn't know\n"
98 " which of the args are paths and not. You will want to use\n"
99 " rebase_path() to convert paths to be relative to the root_build_dir.\n"
100 "\n"
101 " You can dynamically write input dependencies (for incremental rebuilds\n"
102 " if an input file changes) by writing a depfile when the script is run\n"
103 " (see \"gn help depfile\"). This is more flexible than \"inputs\".\n"
104 "\n"
105 " It is recommended you put inputs to your script in the \"sources\"\n"
106 " variable, and stuff like other Python files required to run your\n"
107 " script in the \"inputs\" variable.\n"
108 "\n"
109 ACTION_DEPS
110 "\n"
111 "Outputs\n"
112 "\n"
113 " You should specify files created by your script by specifying them in\n"
114 " the \"outputs\".\n"
115 "\n"
116 SCRIPT_EXECUTION_CONTEXT
117 "\n"
118 "File name handling\n"
119 "\n"
120 SCRIPT_EXECUTION_OUTPUTS
121 "\n"
122 "Variables\n"
123 "\n"
124 " args, data, datadeps, depfile, deps, outputs*, script*,\n"
125 " inputs, sources\n"
126 " * = required\n"
127 "\n"
128 "Example\n"
129 "\n"
130 " action(\"run_this_guy_once\") {\n"
131 " script = \"doprocessing.py\"\n"
132 " sources = [ \"my_configuration.txt\" ]\n"
133 " outputs = [ \"$target_gen_dir/insightful_output.txt\" ]\n"
134 "\n"
135 " # Our script imports this Python file so we want to rebuild if it\n"
136 " # changes.\n"
137 " inputs = [ \"helper_library.py\" ]\n"
138 "\n"
139 " # Note that we have to manually pass the sources to our script if\n"
140 " # the script needs them as inputs.\n"
141 " args = [ \"--out\", rebase_path(target_gen_dir, root_build_dir) ] +\n"
142 " rebase_path(sources, root_build_dir)\n"
143 " }\n";
144
RunAction(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)145 Value RunAction(Scope* scope,
146 const FunctionCallNode* function,
147 const std::vector<Value>& args,
148 BlockNode* block,
149 Err* err) {
150 return ExecuteGenericTarget(functions::kAction, scope, function, args,
151 block, err);
152 }
153
154 // action_foreach --------------------------------------------------------------
155
156 const char kActionForEach[] = "action_foreach";
157 const char kActionForEach_HelpShort[] =
158 "action_foreach: Declare a target that runs a script over a set of files.";
159 const char kActionForEach_Help[] =
160 "action_foreach: Declare a target that runs a script over a set of files.\n"
161 "\n"
162 " This target type allows you to run a script once-per-file over a set\n"
163 " of sources. If you want to run a script once that takes many files as\n"
164 " input, see \"gn help action\".\n"
165 "\n"
166 "Inputs\n"
167 "\n"
168 " The script will be run once per file in the \"sources\" variable. The\n"
169 " \"outputs\" variable should specify one or more files with a source\n"
170 " expansion pattern in it (see \"gn help source_expansion\"). The output\n"
171 " file(s) for each script invocation should be unique. Normally you\n"
172 " use \"{{source_name_part}}\" in each output file.\n"
173 "\n"
174 " If your script takes additional data as input, such as a shared\n"
175 " configuration file or a Python module it uses, those files should be\n"
176 " listed in the \"inputs\" variable. These files are treated as\n"
177 " dependencies of each script invocation.\n"
178 "\n"
179 " You can dynamically write input dependencies (for incremental rebuilds\n"
180 " if an input file changes) by writing a depfile when the script is run\n"
181 " (see \"gn help depfile\"). This is more flexible than \"inputs\".\n"
182 "\n"
183 ACTION_DEPS
184 "\n"
185 "Outputs\n"
186 "\n"
187 SCRIPT_EXECUTION_CONTEXT
188 "\n"
189 "File name handling\n"
190 "\n"
191 SCRIPT_EXECUTION_OUTPUTS
192 "\n"
193 "Variables\n"
194 "\n"
195 " args, data, datadeps, depfile, deps, outputs*, script*,\n"
196 " inputs, sources*\n"
197 " * = required\n"
198 "\n"
199 "Example\n"
200 "\n"
201 " # Runs the script over each IDL file. The IDL script will generate\n"
202 " # both a .cc and a .h file for each input.\n"
203 " action_foreach(\"my_idl\") {\n"
204 " script = \"idl_processor.py\"\n"
205 " sources = [ \"foo.idl\", \"bar.idl\" ]\n"
206 "\n"
207 " # Our script reads this file each time, so we need to list is as a\n"
208 " # dependency so we can rebuild if it changes.\n"
209 " inputs = [ \"my_configuration.txt\" ]\n"
210 "\n"
211 " # Transformation from source file name to output file names.\n"
212 " outputs = [ \"$target_gen_dir/{{source_name_part}}.h\",\n"
213 " \"$target_gen_dir/{{source_name_part}}.cc\" ]\n"
214 "\n"
215 " # Note that since \"args\" is opaque to GN, if you specify paths\n"
216 " # here, you will need to convert it to be relative to the build\n"
217 " # directory using \"rebase_path()\".\n"
218 " args = [\n"
219 " \"{{source}}\",\n"
220 " \"-o\",\n"
221 " rebase_path(relative_target_gen_dir, root_build_dir) +\n"
222 " \"/{{source_name_part}}.h\" ]\n"
223 " }\n"
224 "\n";
RunActionForEach(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)225 Value RunActionForEach(Scope* scope,
226 const FunctionCallNode* function,
227 const std::vector<Value>& args,
228 BlockNode* block,
229 Err* err) {
230 return ExecuteGenericTarget(functions::kActionForEach, scope, function, args,
231 block, err);
232 }
233
234 // component -------------------------------------------------------------------
235
236 const char kComponent[] = "component";
237 const char kComponent_HelpShort[] =
238 "component: Declare a component target.";
239 const char kComponent_Help[] =
240 "component: Declare a component target.\n"
241 "\n"
242 " A component is a shared library, static library, or source set\n"
243 " depending on the component mode. This allows a project to separate\n"
244 " out a build into shared libraries for faster development (link time is\n"
245 " reduced) but to switch to a static build for releases (for better\n"
246 " performance).\n"
247 "\n"
248 " To use this function you must set the value of the \"component_mode\"\n"
249 " variable to one of the following strings:\n"
250 " - \"shared_library\"\n"
251 " - \"static_library\"\n"
252 " - \"source_set\"\n"
253 " It is an error to call \"component\" without defining the mode\n"
254 " (typically this is done in the master build configuration file).\n";
255
RunComponent(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)256 Value RunComponent(Scope* scope,
257 const FunctionCallNode* function,
258 const std::vector<Value>& args,
259 BlockNode* block,
260 Err* err) {
261 // A component is either a shared or static library, depending on the value
262 // of |component_mode|.
263 const Value* component_mode_value =
264 scope->GetValue(variables::kComponentMode);
265
266 static const char helptext[] =
267 "You're declaring a component here but have not defined "
268 "\"component_mode\" to\neither \"shared_library\" or \"static_library\".";
269 if (!component_mode_value) {
270 *err = Err(function->function(), "No component mode set.", helptext);
271 return Value();
272 }
273 if (component_mode_value->type() != Value::STRING ||
274 (component_mode_value->string_value() != functions::kSharedLibrary &&
275 component_mode_value->string_value() != functions::kStaticLibrary &&
276 component_mode_value->string_value() != functions::kSourceSet)) {
277 *err = Err(function->function(), "Invalid component mode set.", helptext);
278 return Value();
279 }
280 const std::string& component_mode = component_mode_value->string_value();
281
282 if (!EnsureNotProcessingImport(function, scope, err))
283 return Value();
284 Scope block_scope(scope);
285 if (!FillTargetBlockScope(scope, function, component_mode.c_str(), block,
286 args, &block_scope, err))
287 return Value();
288
289 block->ExecuteBlockInScope(&block_scope, err);
290 if (err->has_error())
291 return Value();
292
293 TargetGenerator::GenerateTarget(&block_scope, function, args,
294 component_mode, err);
295 return Value();
296 }
297
298 // copy ------------------------------------------------------------------------
299
300 const char kCopy[] = "copy";
301 const char kCopy_HelpShort[] =
302 "copy: Declare a target that copies files.";
303 const char kCopy_Help[] =
304 "copy: Declare a target that copies files.\n"
305 "\n"
306 "File name handling\n"
307 "\n"
308 " All output files must be inside the output directory of the build.\n"
309 " You would generally use |$target_out_dir| or |$target_gen_dir| to\n"
310 " reference the output or generated intermediate file directories,\n"
311 " respectively.\n"
312 "\n"
313 " Both \"sources\" and \"outputs\" must be specified. Sources can\n"
314 " as many files as you want, but there can only be one item in the\n"
315 " outputs list (plural is used for the name for consistency with\n"
316 " other target types).\n"
317 "\n"
318 " If there is more than one source file, your output name should specify\n"
319 " a mapping from each source files to output file names using source\n"
320 " expansion (see \"gn help source_expansion\"). The placeholders will\n"
321 " will look like \"{{source_name_part}}\", for example.\n"
322 "\n"
323 "Examples\n"
324 "\n"
325 " # Write a rule that copies a checked-in DLL to the output directory.\n"
326 " copy(\"mydll\") {\n"
327 " sources = [ \"mydll.dll\" ]\n"
328 " outputs = [ \"$target_out_dir/mydll.dll\" ]\n"
329 " }\n"
330 "\n"
331 " # Write a rule to copy several files to the target generated files\n"
332 " # directory.\n"
333 " copy(\"myfiles\") {\n"
334 " sources = [ \"data1.dat\", \"data2.dat\", \"data3.dat\" ]\n"
335 "\n"
336 " # Use source expansion to generate output files with the\n"
337 " # corresponding file names in the gen dir. This will just copy each\n"
338 " # file.\n"
339 " outputs = [ \"$target_gen_dir/{{source_file_part}}\" ]\n"
340 " }\n";
341
RunCopy(const FunctionCallNode * function,const std::vector<Value> & args,Scope * scope,Err * err)342 Value RunCopy(const FunctionCallNode* function,
343 const std::vector<Value>& args,
344 Scope* scope,
345 Err* err) {
346 if (!EnsureNotProcessingImport(function, scope, err) ||
347 !EnsureNotProcessingBuildConfig(function, scope, err))
348 return Value();
349 TargetGenerator::GenerateTarget(scope, function, args, functions::kCopy, err);
350 return Value();
351 }
352
353 // executable ------------------------------------------------------------------
354
355 const char kExecutable[] = "executable";
356 const char kExecutable_HelpShort[] =
357 "executable: Declare an executable target.";
358 const char kExecutable_Help[] =
359 "executable: Declare an executable target.\n"
360 "\n"
361 "Variables\n"
362 "\n"
363 CONFIG_VALUES_VARS_HELP
364 DEPS_VARS
365 DEPENDENT_CONFIG_VARS
366 GENERAL_TARGET_VARS;
367
RunExecutable(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)368 Value RunExecutable(Scope* scope,
369 const FunctionCallNode* function,
370 const std::vector<Value>& args,
371 BlockNode* block,
372 Err* err) {
373 return ExecuteGenericTarget(functions::kExecutable, scope, function, args,
374 block, err);
375 }
376
377 // group -----------------------------------------------------------------------
378
379 const char kGroup[] = "group";
380 const char kGroup_HelpShort[] =
381 "group: Declare a named group of targets.";
382 const char kGroup_Help[] =
383 "group: Declare a named group of targets.\n"
384 "\n"
385 " This target type allows you to create meta-targets that just collect a\n"
386 " set of dependencies into one named target. Groups can additionally\n"
387 " specify configs that apply to their dependents.\n"
388 "\n"
389 " Depending on a group is exactly like depending directly on that\n"
390 " group's deps. Direct dependent configs will get automatically\n"
391 " forwarded through the group so you shouldn't need to use\n"
392 " \"forward_dependent_configs_from.\n"
393 "\n"
394 "Variables\n"
395 "\n"
396 DEPS_VARS
397 DEPENDENT_CONFIG_VARS
398 "\n"
399 "Example\n"
400 "\n"
401 " group(\"all\") {\n"
402 " deps = [\n"
403 " \"//project:runner\",\n"
404 " \"//project:unit_tests\",\n"
405 " ]\n"
406 " }\n";
407
RunGroup(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)408 Value RunGroup(Scope* scope,
409 const FunctionCallNode* function,
410 const std::vector<Value>& args,
411 BlockNode* block,
412 Err* err) {
413 return ExecuteGenericTarget(functions::kGroup, scope, function, args,
414 block, err);
415 }
416
417 // shared_library --------------------------------------------------------------
418
419 const char kSharedLibrary[] = "shared_library";
420 const char kSharedLibrary_HelpShort[] =
421 "shared_library: Declare a shared library target.";
422 const char kSharedLibrary_Help[] =
423 "shared_library: Declare a shared library target.\n"
424 "\n"
425 " A shared library will be specified on the linker line for targets\n"
426 " listing the shared library in its \"deps\". If you don't want this\n"
427 " (say you dynamically load the library at runtime), then you should\n"
428 " depend on the shared library via \"datadeps\" instead.\n"
429 "\n"
430 "Variables\n"
431 "\n"
432 CONFIG_VALUES_VARS_HELP
433 DEPS_VARS
434 DEPENDENT_CONFIG_VARS
435 GENERAL_TARGET_VARS;
436
RunSharedLibrary(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)437 Value RunSharedLibrary(Scope* scope,
438 const FunctionCallNode* function,
439 const std::vector<Value>& args,
440 BlockNode* block,
441 Err* err) {
442 return ExecuteGenericTarget(functions::kSharedLibrary, scope, function, args,
443 block, err);
444 }
445
446 // source_set ------------------------------------------------------------------
447
448 extern const char kSourceSet[] = "source_set";
449 extern const char kSourceSet_HelpShort[] =
450 "source_set: Declare a source set target.";
451 extern const char kSourceSet_Help[] =
452 "source_set: Declare a source set target.\n"
453 "\n"
454 " A source set is a collection of sources that get compiled, but are not\n"
455 " linked to produce any kind of library. Instead, the resulting object\n"
456 " files are implicitly added to the linker line of all targets that\n"
457 " depend on the source set.\n"
458 "\n"
459 " In most cases, a source set will behave like a static library, except\n"
460 " no actual library file will be produced. This will make the build go\n"
461 " a little faster by skipping creation of a large static library, while\n"
462 " maintaining the organizational benefits of focused build targets.\n"
463 "\n"
464 " The main difference between a source set and a static library is\n"
465 " around handling of exported symbols. Most linkers assume declaring\n"
466 " a function exported means exported from the static library. The linker\n"
467 " can then do dead code elimination to delete code not reachable from\n"
468 " exported functions.\n"
469 "\n"
470 " A source set will not do this code elimination since there is no link\n"
471 " step. This allows you to link many sources sets into a shared library\n"
472 " and have the \"exported symbol\" notation indicate \"export from the\n"
473 " final shared library and not from the intermediate targets.\" There is\n"
474 " no way to express this concept when linking multiple static libraries\n"
475 " into a shared library.\n"
476 "\n"
477 "Variables\n"
478 "\n"
479 CONFIG_VALUES_VARS_HELP
480 DEPS_VARS
481 DEPENDENT_CONFIG_VARS
482 GENERAL_TARGET_VARS;
483
RunSourceSet(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)484 Value RunSourceSet(Scope* scope,
485 const FunctionCallNode* function,
486 const std::vector<Value>& args,
487 BlockNode* block,
488 Err* err) {
489 return ExecuteGenericTarget(functions::kSourceSet, scope, function, args,
490 block, err);
491 }
492
493 // static_library --------------------------------------------------------------
494
495 const char kStaticLibrary[] = "static_library";
496 const char kStaticLibrary_HelpShort[] =
497 "static_library: Declare a static library target.";
498 const char kStaticLibrary_Help[] =
499 "static_library: Declare a static library target.\n"
500 "\n"
501 " Make a \".a\" / \".lib\" file.\n"
502 "\n"
503 " If you only need the static library for intermediate results in the\n"
504 " build, you should consider a source_set instead since it will skip\n"
505 " the (potentially slow) step of creating the intermediate library file.\n"
506 "\n"
507 "Variables\n"
508 "\n"
509 CONFIG_VALUES_VARS_HELP
510 DEPS_VARS
511 DEPENDENT_CONFIG_VARS
512 GENERAL_TARGET_VARS;
513
RunStaticLibrary(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)514 Value RunStaticLibrary(Scope* scope,
515 const FunctionCallNode* function,
516 const std::vector<Value>& args,
517 BlockNode* block,
518 Err* err) {
519 return ExecuteGenericTarget(functions::kStaticLibrary, scope, function, args,
520 block, err);
521 }
522
523 // test ------------------------------------------------------------------------
524
525 const char kTest[] = "test";
526 const char kTest_HelpShort[] =
527 "test: Declares a test target.";
528 const char kTest_Help[] =
529 "test: Declares a test target.\n"
530 "\n"
531 " This is like an executable target, but is named differently to make\n"
532 " the purpose of the target more obvious. It's possible in the future\n"
533 " we can do some enhancements like \"list all of the tests in a given\n"
534 " directory\".\n"
535 "\n"
536 " See \"gn help executable\" for usage.\n";
537
RunTest(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)538 Value RunTest(Scope* scope,
539 const FunctionCallNode* function,
540 const std::vector<Value>& args,
541 BlockNode* block,
542 Err* err) {
543 return ExecuteGenericTarget(functions::kExecutable, scope, function, args,
544 block, err);
545 }
546
547 } // namespace functions
548