• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gn/functions.h"
6 
7 #include "gn/parse_tree.h"
8 #include "gn/scope.h"
9 #include "gn/template.h"
10 #include "gn/value.h"
11 
12 namespace functions {
13 
14 const char kTemplate[] = "template";
15 const char kTemplate_HelpShort[] = "template: Define a template rule.";
16 const char kTemplate_Help[] =
17     R"(template: Define a template rule.
18 
19   A template defines a custom name that acts like a function. It provides a way
20   to add to the built-in target types.
21 
22   The template() function is used to declare a template. To invoke the
23   template, just use the name of the template like any other target type.
24 
25   Often you will want to declare your template in a special file that other
26   files will import (see "gn help import") so your template rule can be shared
27   across build files.
28 
29 Variables and templates:
30 
31   When you call template() it creates a closure around all variables currently
32   in scope with the code in the template block. When the template is invoked,
33   the closure will be executed.
34 
35   When the template is invoked, the code in the caller is executed and passed
36   to the template code as an implicit "invoker" variable. The template uses
37   this to read state out of the invoking code.
38 
39   One thing explicitly excluded from the closure is the "current directory"
40   against which relative file names are resolved. The current directory will be
41   that of the invoking code, since typically that code specifies the file
42   names. This means all files internal to the template should use absolute
43   names.
44 
45   A template will typically forward some or all variables from the invoking
46   scope to a target that it defines. Often, such variables might be optional.
47   Use the pattern:
48 
49     if (defined(invoker.deps)) {
50       deps = invoker.deps
51     }
52 
53   The function forward_variables_from() provides a shortcut to forward one or
54   more or possibly all variables in this manner:
55 
56     forward_variables_from(invoker, ["deps", "public_deps"])
57 
58 Target naming
59 
60   Your template should almost always define a built-in target with the name the
61   template invoker specified. For example, if you have an IDL template and
62   somebody does:
63     idl("foo") {...
64   you will normally want this to expand to something defining a source_set or
65   static_library named "foo" (among other things you may need). This way, when
66   another target specifies a dependency on "foo", the static_library or
67   source_set will be linked.
68 
69   It is also important that any other targets your template expands to have
70   unique names, or you will get collisions.
71 
72   Access the invoking name in your template via the implicit "target_name"
73   variable. This should also be the basis for how other targets that a template
74   expands to ensure uniqueness.
75 
76   A typical example would be a template that defines an action to generate some
77   source files, and a source_set to compile that source. Your template would
78   name the source_set "target_name" because that's what you want external
79   targets to depend on to link your code. And you would name the action
80   something like "${target_name}_action" to make it unique. The source set
81   would have a dependency on the action to make it run.
82 
83 Overriding builtin targets
84 
85   You can use template to redefine a built-in target in which case your template
86   takes a precedence over the built-in one. All uses of the target from within
87   the template definition will refer to the built-in target which makes it
88   possible to extend the behavior of the built-in target:
89 
90     template("shared_library") {
91       shared_library(shlib) {
92         forward_variables_from(invoker, "*")
93         ...
94       }
95     }
96 
97 Example of defining a template
98 
99   template("my_idl") {
100     # Be nice and help callers debug problems by checking that the variables
101     # the template requires are defined. This gives a nice message rather than
102     # giving the user an error about an undefined variable in the file defining
103     # the template
104     #
105     # You can also use defined() to give default values to variables
106     # unspecified by the invoker.
107     assert(defined(invoker.sources),
108            "Need sources in $target_name listing the idl files.")
109 
110     # Name of the intermediate target that does the code gen. This must
111     # incorporate the target name so it's unique across template
112     # instantiations.
113     code_gen_target_name = target_name + "_code_gen"
114 
115     # Intermediate target to convert IDL to C source. Note that the name is
116     # based on the name the invoker of the template specified. This way, each
117     # time the template is invoked we get a unique intermediate action name
118     # (since all target names are in the global scope).
119     action_foreach(code_gen_target_name) {
120       # Access the scope defined by the invoker via the implicit "invoker"
121       # variable.
122       sources = invoker.sources
123 
124       # Note that we need an absolute path for our script file name. The
125       # current directory when executing this code will be that of the invoker
126       # (this is why we can use the "sources" directly above without having to
127       # rebase all of the paths). But if we need to reference a script relative
128       # to the template file, we'll need to use an absolute path instead.
129       script = "//tools/idl/idl_code_generator.py"
130 
131       # Tell GN how to expand output names given the sources.
132       # See "gn help source_expansion" for more.
133       outputs = [ "$target_gen_dir/{{source_name_part}}.cc",
134                   "$target_gen_dir/{{source_name_part}}.h" ]
135     }
136 
137     # Name the source set the same as the template invocation so instancing
138     # this template produces something that other targets can link to in their
139     # deps.
140     source_set(target_name) {
141       # Generates the list of sources, we get these from the action_foreach
142       # above.
143       sources = get_target_outputs(":$code_gen_target_name")
144 
145       # This target depends on the files produced by the above code gen target.
146       deps = [ ":$code_gen_target_name" ]
147     }
148   }
149 
150 Example of invoking the resulting template
151 
152   # This calls the template code above, defining target_name to be
153   # "foo_idl_files" and "invoker" to be the set of stuff defined in the curly
154   # brackets.
155   my_idl("foo_idl_files") {
156     # Goes into the template as "invoker.sources".
157     sources = [ "foo.idl", "bar.idl" ]
158   }
159 
160   # Here is a target that depends on our template.
161   executable("my_exe") {
162     # Depend on the name we gave the template call above. Internally, this will
163     # produce a dependency from executable to the source_set inside the
164     # template (since it has this name), which will in turn depend on the code
165     # gen action.
166     deps = [ ":foo_idl_files" ]
167   }
168 )";
169 
RunTemplate(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)170 Value RunTemplate(Scope* scope,
171                   const FunctionCallNode* function,
172                   const std::vector<Value>& args,
173                   BlockNode* block,
174                   Err* err) {
175   // Of course you can have configs and targets in a template. But here, we're
176   // not actually executing the block, only declaring it. Marking the template
177   // declaration as non-nestable means that you can't put it inside a target,
178   // for example.
179   NonNestableBlock non_nestable(scope, function, "template");
180   if (!non_nestable.Enter(err))
181     return Value();
182 
183   // TODO(brettw) determine if the function is built-in and throw an error if
184   // it is.
185   if (args.size() != 1) {
186     *err =
187         Err(function->function(), "Need exactly one string arg to template.");
188     return Value();
189   }
190   if (!args[0].VerifyTypeIs(Value::STRING, err))
191     return Value();
192   std::string template_name = args[0].string_value();
193 
194   const Template* existing_template = scope->GetTemplate(template_name);
195   if (existing_template) {
196     *err = Err(function, "Duplicate template definition.",
197                "A template with this name was already defined.");
198     err->AppendSubErr(
199         Err(existing_template->GetDefinitionRange(), "Previous definition."));
200     return Value();
201   }
202 
203   scope->AddTemplate(template_name, new Template(scope, function));
204 
205   // The template object above created a closure around the variables in the
206   // current scope. The template code will execute in that context when it's
207   // invoked. But this means that any variables defined above that are used
208   // by the template won't get marked used just by defining the template. The
209   // result can be spurious unused variable errors.
210   //
211   // The "right" thing to do would be to walk the syntax tree inside the
212   // template, find all identifier references, and mark those variables used.
213   // This is annoying and error-prone to implement and takes extra time to run
214   // for this narrow use case.
215   //
216   // Templates are most often defined in .gni files which don't get
217   // used-variable checking anyway, and this case is annoying enough that the
218   // incremental value of unused variable checking isn't worth the
219   // alternatives. So all values in scope before this template definition are
220   // exempted from unused variable checking.
221   scope->MarkAllUsed();
222 
223   return Value();
224 }
225 
226 }  // namespace functions
227