|  | // 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 |