| // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "tools/gn/functions.h" | 
 |  | 
 | #include "tools/gn/parse_tree.h" | 
 | #include "tools/gn/scope.h" | 
 | #include "tools/gn/template.h" | 
 | #include "tools/gn/value.h" | 
 |  | 
 | namespace functions { | 
 |  | 
 | const char kTemplate[] = "template"; | 
 | const char kTemplate_HelpShort[] = | 
 |     "template: Define a template rule."; | 
 | const char kTemplate_Help[] = | 
 |     R"(template: Define a template rule. | 
 |  | 
 |   A template defines a custom name that acts like a function. It provides a way | 
 |   to add to the built-in target types. | 
 |  | 
 |   The template() function is used to declare a template. To invoke the | 
 |   template, just use the name of the template like any other target type. | 
 |  | 
 |   Often you will want to declare your template in a special file that other | 
 |   files will import (see "gn help import") so your template rule can be shared | 
 |   across build files. | 
 |  | 
 | Variables and templates: | 
 |  | 
 |   When you call template() it creates a closure around all variables currently | 
 |   in scope with the code in the template block. When the template is invoked, | 
 |   the closure will be executed. | 
 |  | 
 |   When the template is invoked, the code in the caller is executed and passed | 
 |   to the template code as an implicit "invoker" variable. The template uses | 
 |   this to read state out of the invoking code. | 
 |  | 
 |   One thing explicitly excluded from the closure is the "current directory" | 
 |   against which relative file names are resolved. The current directory will be | 
 |   that of the invoking code, since typically that code specifies the file | 
 |   names. This means all files internal to the template should use absolute | 
 |   names. | 
 |  | 
 |   A template will typically forward some or all variables from the invoking | 
 |   scope to a target that it defines. Often, such variables might be optional. | 
 |   Use the pattern: | 
 |  | 
 |     if (defined(invoker.deps)) { | 
 |       deps = invoker.deps | 
 |     } | 
 |  | 
 |   The function forward_variables_from() provides a shortcut to forward one or | 
 |   more or possibly all variables in this manner: | 
 |  | 
 |     forward_variables_from(invoker, ["deps", "public_deps"]) | 
 |  | 
 | Target naming | 
 |  | 
 |   Your template should almost always define a built-in target with the name the | 
 |   template invoker specified. For example, if you have an IDL template and | 
 |   somebody does: | 
 |     idl("foo") {... | 
 |   you will normally want this to expand to something defining a source_set or | 
 |   static_library named "foo" (among other things you may need). This way, when | 
 |   another target specifies a dependency on "foo", the static_library or | 
 |   source_set will be linked. | 
 |  | 
 |   It is also important that any other targets your template expands to have | 
 |   unique names, or you will get collisions. | 
 |  | 
 |   Access the invoking name in your template via the implicit "target_name" | 
 |   variable. This should also be the basis for how other targets that a template | 
 |   expands to ensure uniqueness. | 
 |  | 
 |   A typical example would be a template that defines an action to generate some | 
 |   source files, and a source_set to compile that source. Your template would | 
 |   name the source_set "target_name" because that's what you want external | 
 |   targets to depend on to link your code. And you would name the action | 
 |   something like "${target_name}_action" to make it unique. The source set | 
 |   would have a dependency on the action to make it run. | 
 |  | 
 | Overriding builtin targets | 
 |  | 
 |   You can use template to redefine a built-in target in which case your template | 
 |   takes a precedence over the built-in one. All uses of the target from within | 
 |   the template definition will refer to the built-in target which makes it | 
 |   possible to extend the behavior of the built-in target: | 
 |  | 
 |     template("shared_library") { | 
 |       shared_library(shlib) { | 
 |         forward_variables_from(invoker, "*") | 
 |         ... | 
 |       } | 
 |     } | 
 |  | 
 | Example of defining a template | 
 |  | 
 |   template("my_idl") { | 
 |     # Be nice and help callers debug problems by checking that the variables | 
 |     # the template requires are defined. This gives a nice message rather than | 
 |     # giving the user an error about an undefined variable in the file defining | 
 |     # the template | 
 |     # | 
 |     # You can also use defined() to give default values to variables | 
 |     # unspecified by the invoker. | 
 |     assert(defined(invoker.sources), | 
 |            "Need sources in $target_name listing the idl files.") | 
 |  | 
 |     # Name of the intermediate target that does the code gen. This must | 
 |     # incorporate the target name so it's unique across template | 
 |     # instantiations. | 
 |     code_gen_target_name = target_name + "_code_gen" | 
 |  | 
 |     # Intermediate target to convert IDL to C source. Note that the name is | 
 |     # based on the name the invoker of the template specified. This way, each | 
 |     # time the template is invoked we get a unique intermediate action name | 
 |     # (since all target names are in the global scope). | 
 |     action_foreach(code_gen_target_name) { | 
 |       # Access the scope defined by the invoker via the implicit "invoker" | 
 |       # variable. | 
 |       sources = invoker.sources | 
 |  | 
 |       # Note that we need an absolute path for our script file name. The | 
 |       # current directory when executing this code will be that of the invoker | 
 |       # (this is why we can use the "sources" directly above without having to | 
 |       # rebase all of the paths). But if we need to reference a script relative | 
 |       # to the template file, we'll need to use an absolute path instead. | 
 |       script = "//tools/idl/idl_code_generator.py" | 
 |  | 
 |       # Tell GN how to expand output names given the sources. | 
 |       # See "gn help source_expansion" for more. | 
 |       outputs = [ "$target_gen_dir/{{source_name_part}}.cc", | 
 |                   "$target_gen_dir/{{source_name_part}}.h" ] | 
 |     } | 
 |  | 
 |     # Name the source set the same as the template invocation so instancing | 
 |     # this template produces something that other targets can link to in their | 
 |     # deps. | 
 |     source_set(target_name) { | 
 |       # Generates the list of sources, we get these from the action_foreach | 
 |       # above. | 
 |       sources = get_target_outputs(":$code_gen_target_name") | 
 |  | 
 |       # This target depends on the files produced by the above code gen target. | 
 |       deps = [ ":$code_gen_target_name" ] | 
 |     } | 
 |   } | 
 |  | 
 | Example of invoking the resulting template | 
 |  | 
 |   # This calls the template code above, defining target_name to be | 
 |   # "foo_idl_files" and "invoker" to be the set of stuff defined in the curly | 
 |   # brackets. | 
 |   my_idl("foo_idl_files") { | 
 |     # Goes into the template as "invoker.sources". | 
 |     sources = [ "foo.idl", "bar.idl" ] | 
 |   } | 
 |  | 
 |   # Here is a target that depends on our template. | 
 |   executable("my_exe") { | 
 |     # Depend on the name we gave the template call above. Internally, this will | 
 |     # produce a dependency from executable to the source_set inside the | 
 |     # template (since it has this name), which will in turn depend on the code | 
 |     # gen action. | 
 |     deps = [ ":foo_idl_files" ] | 
 |   } | 
 | )"; | 
 |  | 
 | Value RunTemplate(Scope* scope, | 
 |                   const FunctionCallNode* function, | 
 |                   const std::vector<Value>& args, | 
 |                   BlockNode* block, | 
 |                   Err* err) { | 
 |   // Of course you can have configs and targets in a template. But here, we're | 
 |   // not actually executing the block, only declaring it. Marking the template | 
 |   // declaration as non-nestable means that you can't put it inside a target, | 
 |   // for example. | 
 |   NonNestableBlock non_nestable(scope, function, "template"); | 
 |   if (!non_nestable.Enter(err)) | 
 |     return Value(); | 
 |  | 
 |   // TODO(brettw) determine if the function is built-in and throw an error if | 
 |   // it is. | 
 |   if (args.size() != 1) { | 
 |     *err = Err(function->function(), | 
 |                "Need exactly one string arg to template."); | 
 |     return Value(); | 
 |   } | 
 |   if (!args[0].VerifyTypeIs(Value::STRING, err)) | 
 |     return Value(); | 
 |   std::string template_name = args[0].string_value(); | 
 |  | 
 |   const Template* existing_template = scope->GetTemplate(template_name); | 
 |   if (existing_template) { | 
 |     *err = Err(function, "Duplicate template definition.", | 
 |                "A template with this name was already defined."); | 
 |     err->AppendSubErr(Err(existing_template->GetDefinitionRange(), | 
 |                           "Previous definition.")); | 
 |     return Value(); | 
 |   } | 
 |  | 
 |   scope->AddTemplate(template_name, new Template(scope, function)); | 
 |  | 
 |   // The template object above created a closure around the variables in the | 
 |   // current scope. The template code will execute in that context when it's | 
 |   // invoked. But this means that any variables defined above that are used | 
 |   // by the template won't get marked used just by defining the template. The | 
 |   // result can be spurious unused variable errors. | 
 |   // | 
 |   // The "right" thing to do would be to walk the syntax tree inside the | 
 |   // template, find all identifier references, and mark those variables used. | 
 |   // This is annoying and error-prone to implement and takes extra time to run | 
 |   // for this narrow use case. | 
 |   // | 
 |   // Templates are most often defined in .gni files which don't get | 
 |   // used-variable checking anyway, and this case is annoying enough that the | 
 |   // incremental value of unused variable checking isn't worth the | 
 |   // alternatives. So all values in scope before this template definition are | 
 |   // exempted from unused variable checking. | 
 |   scope->MarkAllUsed(); | 
 |  | 
 |   return Value(); | 
 | } | 
 |  | 
 | }  // namespace functions |