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/parse_tree.h"
8#include "tools/gn/scope.h"
9#include "tools/gn/value.h"
10
11namespace functions {
12
13const char kTemplate[] = "template";
14const char kTemplate_Help[] =
15    "template: Define a template rule.\n"
16    "\n"
17    "  A template defines a custom rule name that can expand to one or more\n"
18    "  other rules (typically built-in rules like \"static_library\"). It\n"
19    "  provides a way to add to the built-in target types.\n"
20    "\n"
21    "  The template() function is used to declare a template. To invoke the\n"
22    "  template, just use the name of the template like any other target\n"
23    "  type.\n"
24    "\n"
25    "More details:\n"
26    "\n"
27    "  Semantically, the code in the template is stored. When a function\n"
28    "  with the name is called, the block following the invocation is\n"
29    "  executed, *then* your template code is executed. So if the invocation\n"
30    "  sets the |source| variable, for example, that variable will be\n"
31    "  accessible to you when the template code runs.\n"
32    "\n"
33    "  The template() function does not generate a closure, so the\n"
34    "  environment, current directory, etc. will all be the same as from\n"
35    "  the template is invoked.\n"
36    "\n"
37    "Hints:\n"
38    "\n"
39    "  If your template expands to more than one target, be sure to name\n"
40    "  the intermediate targets based on the name of the template\n"
41    "  instantiation so that the names are globally unique. The variable\n"
42    "  |target_name| will be this name.\n"
43    "\n"
44    "  Likewise, you will always want to generate a target in your template\n"
45    "  with the original |target_name|. Otherwise, invoking your template\n"
46    "  will not actually generate a node in the dependency graph that other\n"
47    "  targets can reference.\n"
48    "\n"
49    "  Often you will want to declare your template in a special file that\n"
50    "  other files will import (see \"gn help import\") so your template\n"
51    "  rule can be shared across build files.\n"
52    "\n"
53    "Example of defining a template:\n"
54    "\n"
55    "  template(\"my_idl\") {\n"
56    "    # Maps input files to output files, used in both targets below.\n"
57    "    filter = [ \"$target_gen_dir/{{source_name_part}}.cc\",\n"
58    "               \"$target_gen_dir/{{source_name_part}}.h\" ]\n"
59    "\n"
60    "    # Intermediate target to compile IDL to C source.\n"
61    "    custom(\"${target_name}_code_gen\") {\n"
62    "      # The |sources| will be inherited from the surrounding scope so\n"
63    "      # we don't need to redefine it.\n"
64    "      script = \"foo.py\"\n"
65    "      outputs = filter  # Variable from above.\n"
66    "    }\n"
67    "\n"
68    "    # Name the static library the same as the template invocation so\n"
69    "    # instanting this template produces something that other targets\n"
70    "    # can link to in their deps.\n"
71    "    static_library(target_name) {\n"
72    "      # Generates the list of sources.\n"
73    "      # See \"gn help process_file_template\"\n"
74    "      sources = process_file_template(sources, filter)\n"
75    "    }\n"
76    "  }\n"
77    "\n"
78    "Example of invoking the resulting template:\n"
79    "\n"
80    "  my_idl(\"foo_idl_files\") {\n"
81    "    sources = [ \"foo.idl\", \"bar.idl\" ]\n"
82    "  }\n";
83
84Value RunTemplate(Scope* scope,
85                  const FunctionCallNode* function,
86                  const std::vector<Value>& args,
87                  BlockNode* block,
88                  Err* err) {
89  // TODO(brettw) determine if the function is built-in and throw an error if
90  // it is.
91  if (args.size() != 1) {
92    *err = Err(function->function(),
93               "Need exactly one string arg to template.");
94    return Value();
95  }
96  if (!args[0].VerifyTypeIs(Value::STRING, err))
97    return Value();
98  std::string template_name = args[0].string_value();
99
100  const FunctionCallNode* existing_template = scope->GetTemplate(template_name);
101  if (existing_template) {
102    *err = Err(function, "Duplicate template definition.",
103               "A template with this name was already defined.");
104    err->AppendSubErr(Err(existing_template->function(),
105                          "Previous definition."));
106    return Value();
107  }
108
109  scope->AddTemplate(template_name, function);
110  return Value();
111}
112
113}  // namespace functions
114