summaryrefslogtreecommitdiffstats
path: root/tools/gn/function_template.cc
blob: 9e78432408eace4009dc1917f32c98231b94d12d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// 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