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, external, source_prereqs, sources\n"
21
22namespace functions {
23
24namespace {
25
26Value 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// component -------------------------------------------------------------------
56
57const char kComponent[] = "component";
58const char kComponent_Help[] =
59    "component: Declare a component target.\n"
60    "\n"
61    "  A component is a shared library, static library, or source set\n"
62    "  depending on the component mode. This allows a project to separate\n"
63    "  out a build into shared libraries for faster devlopment (link time is\n"
64    "  reduced) but to switch to a static build for releases (for better\n"
65    "  performance).\n"
66    "\n"
67    "  To use this function you must set the value of the \"component_mode\n"
68    "  variable to one of the following strings:\n"
69    "    - \"shared_library\"\n"
70    "    - \"static_library\"\n"
71    "    - \"source_set\"\n"
72    "  It is an error to call \"component\" without defining the mode\n"
73    "  (typically this is done in the master build configuration file).\n";
74
75Value RunComponent(Scope* scope,
76                   const FunctionCallNode* function,
77                   const std::vector<Value>& args,
78                   BlockNode* block,
79                   Err* err) {
80  // A component is either a shared or static library, depending on the value
81  // of |component_mode|.
82  const Value* component_mode_value =
83      scope->GetValue(variables::kComponentMode);
84
85  static const char helptext[] =
86      "You're declaring a component here but have not defined "
87      "\"component_mode\" to\neither \"shared_library\" or \"static_library\".";
88  if (!component_mode_value) {
89    *err = Err(function->function(), "No component mode set.", helptext);
90    return Value();
91  }
92  if (component_mode_value->type() != Value::STRING ||
93      (component_mode_value->string_value() != functions::kSharedLibrary &&
94       component_mode_value->string_value() != functions::kStaticLibrary &&
95       component_mode_value->string_value() != functions::kSourceSet)) {
96    *err = Err(function->function(), "Invalid component mode set.", helptext);
97    return Value();
98  }
99  const std::string& component_mode = component_mode_value->string_value();
100
101  if (!EnsureNotProcessingImport(function, scope, err))
102    return Value();
103  Scope block_scope(scope);
104  if (!FillTargetBlockScope(scope, function, component_mode.c_str(), block,
105                            args, &block_scope, err))
106    return Value();
107
108  block->ExecuteBlockInScope(&block_scope, err);
109  if (err->has_error())
110    return Value();
111
112  TargetGenerator::GenerateTarget(&block_scope, function, args,
113                                  component_mode, err);
114  return Value();
115}
116
117// copy ------------------------------------------------------------------------
118
119const char kCopy[] = "copy";
120const char kCopy_Help[] =
121    "copy: Declare a target that copies files.\n"
122    "\n"
123    "File name handling\n"
124    "\n"
125    "  All output files must be inside the output directory of the build.\n"
126    "  You would generally use |$target_out_dir| or |$target_gen_dir| to\n"
127    "  reference the output or generated intermediate file directories,\n"
128    "  respectively.\n"
129    "\n"
130    "  Both \"sources\" and \"outputs\" must be specified. Sources can\n"
131    "  as many files as you want, but there can only be one item in the\n"
132    "  outputs list (plural is used for the name for consistency with\n"
133    "  other target types).\n"
134    "\n"
135    "  If there is more than one source file, your output name should specify\n"
136    "  a mapping from each source files to output file names using source\n"
137    "  expansion (see \"gn help source_expansion\"). The placeholders will\n"
138    "  will look like \"{{source_name_part}}\", for example.\n"
139    "\n"
140    "Examples\n"
141    "\n"
142    "  # Write a rule that copies a checked-in DLL to the output directory.\n"
143    "  copy(\"mydll\") {\n"
144    "    sources = [ \"mydll.dll\" ]\n"
145    "    outputs = [ \"$target_out_dir/mydll.dll\" ]\n"
146    "  }\n"
147    "\n"
148    "  # Write a rule to copy several files to the target generated files\n"
149    "  # directory.\n"
150    "  copy(\"myfiles\") {\n"
151    "    sources = [ \"data1.dat\", \"data2.dat\", \"data3.dat\" ]\n"
152    "\n"
153    "    # Use source expansion to generate output files with the\n"
154    "    # corresponding file names in the gen dir. This will just copy each\n"
155    "    # file.\n"
156    "    outputs = [ \"$target_gen_dir/{{source_file_part}}\" ]\n"
157    "  }\n";
158
159Value RunCopy(const FunctionCallNode* function,
160              const std::vector<Value>& args,
161              Scope* scope,
162              Err* err) {
163  if (!EnsureNotProcessingImport(function, scope, err) ||
164      !EnsureNotProcessingBuildConfig(function, scope, err))
165    return Value();
166  TargetGenerator::GenerateTarget(scope, function, args, functions::kCopy, err);
167  return Value();
168}
169
170// custom ----------------------------------------------------------------------
171
172const char kCustom[] = "custom";
173const char kCustom_Help[] =
174    "custom: Declare a script-generated target.\n"
175    "\n"
176    "  This target type allows you to run a script over a set of source\n"
177    "  files and generate a set of output files.\n"
178    "\n"
179    "  The script will be executed with the given arguments with the current\n"
180    "  directory being that of the root build directory. If you pass files\n"
181    "  to your script, see \"gn help to_build_path\" for how to convert\n"
182    "  file names to be relative to the build directory (file names in the\n"
183    "  sources, outputs, and source_prereqs will be all treated as relative\n"
184    "  to the current build file and converted as needed automatically).\n"
185    "\n"
186    "  There are two modes. The first mode is the \"per-file\" mode where you\n"
187    "  specify a list of sources and the script is run once for each one as a\n"
188    "  build rule. In this case, each file specified in the |outputs|\n"
189    "  variable must be unique when applied to each source file (normally you\n"
190    "  would reference |{{source_name_part}}| from within each one) or the\n"
191    "  build system will get confused about how to build those files. You\n"
192    "  should use the |source_prereqs| variable to list all additional\n"
193    "  dependencies of your script: these will be added as dependencies for\n"
194    "  each build step.\n"
195    "\n"
196    "  The second mode is when you just want to run a script once rather than\n"
197    "  as a general rule over a set of files. In this case you don't list any\n"
198    "  sources. Dependencies of your script are specified only in the\n"
199    "  |source_prereqs| variable and your |outputs| variable should just list\n"
200    "  all outputs.\n"
201    "\n"
202    "File name handling\n"
203    "\n"
204    "  All output files must be inside the output directory of the build.\n"
205    "  You would generally use |$target_out_dir| or |$target_gen_dir| to\n"
206    "  reference the output or generated intermediate file directories,\n"
207    "  respectively.\n"
208    "\n"
209    "  You can specify a mapping from source files to output files using\n"
210    "  source expansion (see \"gn help source_expansion\"). The placeholders\n"
211    "  will look like \"{{source}}\", for example, and can appear in\n"
212    "  either the outputs or the args lists.\n"
213    "\n"
214    "Variables\n"
215    "\n"
216    "  args, deps, outputs, script*, source_prereqs, sources\n"
217    "  * = required\n"
218    "\n"
219    "Examples\n"
220    "\n"
221    "  # Runs the script over each IDL file. The IDL script will generate\n"
222    "  # both a .cc and a .h file for each input.\n"
223    "  custom(\"general_rule\") {\n"
224    "    script = \"idl_processor.py\"\n"
225    "    sources = [ \"foo.idl\", \"bar.idl\" ]\n"
226    "    source_prereqs = [ \"my_configuration.txt\" ]\n"
227    "    outputs = [ \"$target_gen_dir/{{source_name_part}}.h\",\n"
228    "                \"$target_gen_dir/{{source_name_part}}.cc\" ]\n"
229    "\n"
230    "    # Note that since \"args\" is opaque to GN, if you specify paths\n"
231    "    # here, you will need to convert it to be relative to the build\n"
232    "    # directory using \"to_build_path()\".\n"
233    "    args = [ \"{{source}}\",\n"
234    "             \"-o\",\n"
235    "             to_build_path(relative_target_gen_dir) + \"/\" +\n"
236    "                 {{source_name_part}}.h\" ]\n"
237    "  }\n"
238    "\n"
239    "  custom(\"just_run_this_guy_once\") {\n"
240    "    script = \"doprocessing.py\"\n"
241    "    source_prereqs = [ \"my_configuration.txt\" ]\n"
242    "    outputs = [ \"$target_gen_dir/insightful_output.txt\" ]\n"
243    "    args = [ \"--output_dir\", to_build_path(target_gen_dir) ]\n"
244    "  }\n";
245
246Value RunCustom(Scope* scope,
247                const FunctionCallNode* function,
248                const std::vector<Value>& args,
249                BlockNode* block,
250                Err* err) {
251  return ExecuteGenericTarget(functions::kCustom, scope, function, args,
252                              block, err);
253}
254
255// executable ------------------------------------------------------------------
256
257const char kExecutable[] = "executable";
258const char kExecutable_Help[] =
259    "executable: Declare an executable target.\n"
260    "\n"
261    "Variables\n"
262    "\n"
263    CONFIG_VALUES_VARS_HELP
264    DEPS_VARS
265    DEPENDENT_CONFIG_VARS
266    GENERAL_TARGET_VARS;
267
268Value RunExecutable(Scope* scope,
269                    const FunctionCallNode* function,
270                    const std::vector<Value>& args,
271                    BlockNode* block,
272                    Err* err) {
273  return ExecuteGenericTarget(functions::kExecutable, scope, function, args,
274                              block, err);
275}
276
277// group -----------------------------------------------------------------------
278
279const char kGroup[] = "group";
280const char kGroup_Help[] =
281    "group: Declare a named group of targets.\n"
282    "\n"
283    "  This target type allows you to create meta-targets that just collect a\n"
284    "  set of dependencies into one named target. Groups can additionally\n"
285    "  specify configs that apply to their dependents.\n"
286    "\n"
287    "  Depending on a group is exactly like depending directly on that\n"
288    "  group's deps. Direct dependent configs will get automatically fowarded\n"
289    "  through the group so you shouldn't need to use\n"
290    "  \"forward_dependent_configs_from.\n"
291    "\n"
292    "Variables\n"
293    "\n"
294    DEPS_VARS
295    DEPENDENT_CONFIG_VARS
296    "  Other variables: external\n"
297    "\n"
298    "Example\n"
299    "\n"
300    "  group(\"all\") {\n"
301    "    deps = [\n"
302    "      \"//project:runner\",\n"
303    "      \"//project:unit_tests\",\n"
304    "    ]\n"
305    "  }\n";
306
307Value RunGroup(Scope* scope,
308               const FunctionCallNode* function,
309               const std::vector<Value>& args,
310               BlockNode* block,
311               Err* err) {
312  return ExecuteGenericTarget(functions::kGroup, scope, function, args,
313                              block, err);
314}
315
316// shared_library --------------------------------------------------------------
317
318const char kSharedLibrary[] = "shared_library";
319const char kSharedLibrary_Help[] =
320    "shared_library: Declare a shared library target.\n"
321    "\n"
322    "  A shared library will be specified on the linker line for targets\n"
323    "  listing the shared library in its \"deps\". If you don't want this\n"
324    "  (say you dynamically load the library at runtime), then you should\n"
325    "  depend on the shared library via \"datadeps\" instead.\n"
326    "\n"
327    "Variables\n"
328    "\n"
329    CONFIG_VALUES_VARS_HELP
330    DEPS_VARS
331    DEPENDENT_CONFIG_VARS
332    GENERAL_TARGET_VARS;
333
334Value RunSharedLibrary(Scope* scope,
335                       const FunctionCallNode* function,
336                       const std::vector<Value>& args,
337                       BlockNode* block,
338                       Err* err) {
339  return ExecuteGenericTarget(functions::kSharedLibrary, scope, function, args,
340                              block, err);
341}
342
343// source_set ------------------------------------------------------------------
344
345extern const char kSourceSet[] = "source_set";
346extern const char kSourceSet_Help[] =
347    "source_set: Declare a source set target.\n"
348    "\n"
349    "  A source set is a collection of sources that get compiled, but are not\n"
350    "  linked to produce any kind of library. Instead, the resulting object\n"
351    "  files are implicitly added to the linker line of all targets that\n"
352    "  depend on the source set.\n"
353    "\n"
354    "  In most cases, a source set will behave like a static library, except\n"
355    "  no actual library file will be produced. This will make the build go\n"
356    "  a little faster by skipping creation of a large static library, while\n"
357    "  maintaining the organizational benefits of focused build targets.\n"
358    "\n"
359    "  The main difference between a source set and a static library is\n"
360    "  around handling of exported symbols. Most linkers assume declaring\n"
361    "  a function exported means exported from the static library. The linker\n"
362    "  can then do dead code elimination to delete code not reachable from\n"
363    "  exported functions.\n"
364    "\n"
365    "  A source set will not do this code elimination since there is no link\n"
366    "  step. This allows you to link many sources sets into a shared library\n"
367    "  and have the \"exported symbol\" notation indicate \"export from the\n"
368    "  final shared library and not from the intermediate targets.\" There is\n"
369    "  no way to express this concept when linking multiple static libraries\n"
370    "  into a shared library.\n"
371    "\n"
372    "Variables\n"
373    "\n"
374    CONFIG_VALUES_VARS_HELP
375    DEPS_VARS
376    DEPENDENT_CONFIG_VARS
377    GENERAL_TARGET_VARS;
378
379Value RunSourceSet(Scope* scope,
380                   const FunctionCallNode* function,
381                   const std::vector<Value>& args,
382                   BlockNode* block,
383                   Err* err) {
384  return ExecuteGenericTarget(functions::kSourceSet, scope, function, args,
385                              block, err);
386}
387
388// static_library --------------------------------------------------------------
389
390const char kStaticLibrary[] = "static_library";
391const char kStaticLibrary_Help[] =
392    "static_library: Declare a static library target.\n"
393    "\n"
394    "  Make a \".a\" / \".lib\" file.\n"
395    "\n"
396    "  If you only need the static library for intermediate results in the\n"
397    "  build, you should consider a source_set instead since it will skip\n"
398    "  the (potentially slow) step of creating the intermediate library file.\n"
399    "\n"
400    "Variables\n"
401    "\n"
402    CONFIG_VALUES_VARS_HELP
403    DEPS_VARS
404    DEPENDENT_CONFIG_VARS
405    GENERAL_TARGET_VARS;
406
407Value RunStaticLibrary(Scope* scope,
408                       const FunctionCallNode* function,
409                       const std::vector<Value>& args,
410                       BlockNode* block,
411                       Err* err) {
412  return ExecuteGenericTarget(functions::kStaticLibrary, scope, function, args,
413                              block, err);
414}
415
416// test ------------------------------------------------------------------------
417
418const char kTest[] = "test";
419const char kTest_Help[] =
420    "test: Declares a test target.\n"
421    "\n"
422    "  This is like an executable target, but is named differently to make\n"
423    "  the purpose of the target more obvious. It's possible in the future\n"
424    "  we can do some enhancements like \"list all of the tests in a given\n"
425    "  directory\".\n"
426    "\n"
427    "  See \"gn help executable\" for usage.\n";
428
429Value RunTest(Scope* scope,
430              const FunctionCallNode* function,
431              const std::vector<Value>& args,
432              BlockNode* block,
433              Err* err) {
434  return ExecuteGenericTarget(functions::kExecutable, scope, function, args,
435                              block, err);
436}
437
438}  // namespace functions
439