| // 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/value.h" |
| |
| namespace functions { |
| |
| const char kTemplate[] = "template"; |
| const char kTemplate_Help[] = |
| "template: Define a template rule.\n" |
| "\n" |
| " A template defines a custom rule name that can expand to one or more\n" |
| " other rules (typically built-in rules like \"static_library\"). It\n" |
| " provides a way to add to the built-in target types.\n" |
| "\n" |
| " The template() function is used to declare a template. To invoke the\n" |
| " template, just use the name of the template like any other target\n" |
| " type.\n" |
| "\n" |
| "More details:\n" |
| "\n" |
| " Semantically, the code in the template is stored. When a function\n" |
| " with the name is called, the block following the invocation is\n" |
| " executed, *then* your template code is executed. So if the invocation\n" |
| " sets the |source| variable, for example, that variable will be\n" |
| " accessible to you when the template code runs.\n" |
| "\n" |
| " The template() function does not generate a closure, so the\n" |
| " environment, current directory, etc. will all be the same as from\n" |
| " the template is invoked.\n" |
| "\n" |
| "Hints:\n" |
| "\n" |
| " If your template expands to more than one target, be sure to name\n" |
| " the intermediate targets based on the name of the template\n" |
| " instantiation so that the names are globally unique. The variable\n" |
| " |target_name| will be this name.\n" |
| "\n" |
| " Likewise, you will always want to generate a target in your template\n" |
| " with the original |target_name|. Otherwise, invoking your template\n" |
| " will not actually generate a node in the dependency graph that other\n" |
| " targets can reference.\n" |
| "\n" |
| " Often you will want to declare your template in a special file that\n" |
| " other files will import (see \"gn help import\") so your template\n" |
| " rule can be shared across build files.\n" |
| "\n" |
| "Example of defining a template:\n" |
| "\n" |
| " template(\"my_idl\") {\n" |
| " # Maps input files to output files, used in both targets below.\n" |
| " filter = [ \"$target_gen_dir/{{source_name_part}}.cc\",\n" |
| " \"$target_gen_dir/{{source_name_part}}.h\" ]\n" |
| "\n" |
| " # Intermediate target to compile IDL to C source.\n" |
| " custom(\"${target_name}_code_gen\") {\n" |
| " # The |sources| will be inherited from the surrounding scope so\n" |
| " # we don't need to redefine it.\n" |
| " script = \"foo.py\"\n" |
| " outputs = filter # Variable from above.\n" |
| " }\n" |
| "\n" |
| " # Name the static library the same as the template invocation so\n" |
| " # instanting this template produces something that other targets\n" |
| " # can link to in their deps.\n" |
| " static_library(target_name) {\n" |
| " # Generates the list of sources.\n" |
| " # See \"gn help process_file_template\"\n" |
| " sources = process_file_template(sources, filter)\n" |
| " }\n" |
| " }\n" |
| "\n" |
| "Example of invoking the resulting template:\n" |
| "\n" |
| " my_idl(\"foo_idl_files\") {\n" |
| " sources = [ \"foo.idl\", \"bar.idl\" ]\n" |
| " }\n"; |
| |
| Value RunTemplate(Scope* scope, |
| const FunctionCallNode* function, |
| const std::vector<Value>& args, |
| BlockNode* block, |
| Err* err) { |
| // 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 FunctionCallNode* 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->function(), |
| "Previous definition.")); |
| return Value(); |
| } |
| |
| scope->AddTemplate(template_name, function); |
| return Value(); |
| } |
| |
| } // namespace functions |