OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/functions.h" | 5 #include "tools/gn/functions.h" |
6 | 6 |
7 #include "tools/gn/parse_tree.h" | 7 #include "tools/gn/parse_tree.h" |
8 #include "tools/gn/scope.h" | 8 #include "tools/gn/scope.h" |
| 9 #include "tools/gn/template.h" |
9 #include "tools/gn/value.h" | 10 #include "tools/gn/value.h" |
10 | 11 |
11 namespace functions { | 12 namespace functions { |
12 | 13 |
13 const char kTemplate[] = "template"; | 14 const char kTemplate[] = "template"; |
14 const char kTemplate_Help[] = | 15 const char kTemplate_Help[] = |
15 "template: Define a template rule.\n" | 16 "template: Define a template rule.\n" |
16 "\n" | 17 "\n" |
17 " A template defines a custom rule name that can expand to one or more\n" | 18 " A template defines a custom name that acts like a function. It\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" | 19 " provides a way to add to the built-in target types.\n" |
20 "\n" | 20 "\n" |
21 " The template() function is used to declare a template. To invoke the\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" | 22 " template, just use the name of the template like any other target\n" |
23 " type.\n" | 23 " type.\n" |
24 "\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" | 25 " 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" | 26 " other files will import (see \"gn help import\") so your template\n" |
51 " rule can be shared across build files.\n" | 27 " rule can be shared across build files.\n" |
52 "\n" | 28 "\n" |
| 29 "More details:\n" |
| 30 "\n" |
| 31 " When you call template() it creates a closure around all variables\n" |
| 32 " currently in scope with the code in the template block. When the\n" |
| 33 " template is invoked, the closure will be executed.\n" |
| 34 "\n" |
| 35 " When the template is invoked, the code in the caller is executed and\n" |
| 36 " passed to the template code as an implicit \"invoker\" variable. The\n" |
| 37 " template uses this to read state out of the invoking code.\n" |
| 38 "\n" |
| 39 " One thing explicitly excluded from the closure is the \"current\n" |
| 40 " directory\" against which relative file names are resolved. The\n" |
| 41 " current directory will be that of the invoking code, since typically\n" |
| 42 " that code specifies the file names. This means all files internal\n" |
| 43 " to the template should use absolute names.\n" |
| 44 "\n" |
| 45 "Target naming:\n" |
| 46 "\n" |
| 47 " Your template should almost always define a built-in target with the\n" |
| 48 " name the template invoker specified. For example, if you have an IDL\n" |
| 49 " template and somebody does:\n" |
| 50 " idl(\"foo\") {...\n" |
| 51 " you will normally want this to expand to something defining a\n" |
| 52 " source_set or static_library named \"foo\" (among other things you may\n" |
| 53 " need). This way, when another target specifies a dependency on\n" |
| 54 " \"foo\", the static_library or source_set will be linked.\n" |
| 55 "\n" |
| 56 " It is also important that any other targets your template expands to\n" |
| 57 " have globally unique names, or you will get collisions.\n" |
| 58 "\n" |
| 59 " Access the invoking name in your template via the implicit\n" |
| 60 " \"target_name\" variable. This should also be the basis of how other\n" |
| 61 " targets that a template expands to to ensure uniquness.\n" |
| 62 "\n" |
| 63 " A typical example would be a template that defines an action to\n" |
| 64 " generate some source files, and a source_set to compile that source.\n" |
| 65 " Your template would name the source_set \"target_name\" because\n" |
| 66 " that's what you want external targets to depend on to link your code.\n" |
| 67 " And you would name the action something like \"${target_name}_action\"\n" |
| 68 " to make it unique. The source set would have a dependency on the\n" |
| 69 " action to make it run.\n" |
| 70 "\n" |
53 "Example of defining a template:\n" | 71 "Example of defining a template:\n" |
54 "\n" | 72 "\n" |
55 " template(\"my_idl\") {\n" | 73 " template(\"my_idl\") {\n" |
56 " # Maps input files to output files, used in both targets below.\n" | 74 " # Be nice and help callers debug problems by checking that the\n" |
| 75 " # variables the template requires are defined. This gives a nice\n" |
| 76 " # message rather than giving the user an error about an\n" |
| 77 " # undefined variable in the file defining the template\n" |
| 78 " #\n" |
| 79 " # You can also use defined() to give default values to variables\n" |
| 80 " # unspecified by the invoker.\n" |
| 81 " assert(defined(invoker.sources),\n" |
| 82 " \"Need sources in $target_name listing the idl files.\")\n" |
| 83 "\n" |
| 84 " # Define a variable containing a source expansion\n" |
| 85 " # (see \"gn help source_expansion\") that maps input files to\n" |
| 86 " # output files. It is used in both targets below.\n" |
57 " filter = [ \"$target_gen_dir/{{source_name_part}}.cc\",\n" | 87 " filter = [ \"$target_gen_dir/{{source_name_part}}.cc\",\n" |
58 " \"$target_gen_dir/{{source_name_part}}.h\" ]\n" | 88 " \"$target_gen_dir/{{source_name_part}}.h\" ]\n" |
59 "\n" | 89 "\n" |
60 " # Intermediate target to compile IDL to C source.\n" | 90 " # Intermediate target to convert IDL to C source. Note that the name\n" |
| 91 " # is based on the name the invoker of the template specified. This\n" |
| 92 " # way, each time the template is invoked we get a unique\n" |
| 93 " # intermediate action name (since all target names are in the global\n" |
| 94 " # scope).\n" |
61 " action_foreach(\"${target_name}_code_gen\") {\n" | 95 " action_foreach(\"${target_name}_code_gen\") {\n" |
62 " # The |sources| will be inherited from the surrounding scope so\n" | 96 " # Access the scope defined by the invoker via the implicit\n" |
63 " # we don't need to redefine it.\n" | 97 " # \"invoker\" variable.\n" |
64 " script = \"foo.py\"\n" | 98 " sources = invoker.sources\n" |
| 99 "\n" |
| 100 " # Note that we need an absolute path for our script file name.\n" |
| 101 " # The current directory when executing this code will be that of\n" |
| 102 " # the invoker (this is why we can use the \"sources\" directly\n" |
| 103 " # above without having to rebase all of the paths). But if we need\n" |
| 104 " # to reference a script relative to the template file, we'll need\n" |
| 105 " # to use an absolute path instead.\n" |
| 106 " script = \"//tools/idl/idl_code_generator.py\"\n" |
65 " outputs = filter # Variable from above.\n" | 107 " outputs = filter # Variable from above.\n" |
66 " }\n" | 108 " }\n" |
67 "\n" | 109 "\n" |
68 " # Name the static library the same as the template invocation so\n" | 110 " # Name the source set the same as the template invocation so\n" |
69 " # instancing this template produces something that other targets\n" | 111 " # instancing this template produces something that other targets\n" |
70 " # can link to in their deps.\n" | 112 " # can link to in their deps.\n" |
71 " static_library(target_name) {\n" | 113 " source_set(target_name) {\n" |
72 " # Generates the list of sources.\n" | 114 " # Generates the list of sources.\n" |
73 " # See \"gn help process_file_template\"\n" | 115 " # See \"gn help process_file_template\"\n" |
74 " sources = process_file_template(sources, filter)\n" | 116 " sources = process_file_template(invoker.sources, filter)\n" |
| 117 "\n" |
| 118 " # This target depends on the files produced by the above code gen\n" |
| 119 " # target.\n" |
| 120 " deps = [ \":${target_name}_code_gen\" ]\n" |
75 " }\n" | 121 " }\n" |
76 " }\n" | 122 " }\n" |
77 "\n" | 123 "\n" |
78 "Example of invoking the resulting template:\n" | 124 "Example of invoking the resulting template:\n" |
79 "\n" | 125 "\n" |
| 126 " # This calls the template code above, defining target_name to be\n" |
| 127 " # \"foo_idl_files\" and \"invoker\" to be the set of stuff defined in\n" |
| 128 " # the curly brackets.\n" |
80 " my_idl(\"foo_idl_files\") {\n" | 129 " my_idl(\"foo_idl_files\") {\n" |
| 130 " # Goes into the template as \"invoker.sources\".\n" |
81 " sources = [ \"foo.idl\", \"bar.idl\" ]\n" | 131 " sources = [ \"foo.idl\", \"bar.idl\" ]\n" |
| 132 " }\n" |
| 133 "\n" |
| 134 " # Here is a target that depends on our template.\n" |
| 135 " executable(\"my_exe\") {\n" |
| 136 " # Depend on the name we gave the template call above. Internally,\n" |
| 137 " # this will produce a dependency from executable to the source_set\n" |
| 138 " # inside the template (since it has this name), which will in turn\n" |
| 139 " # depend on the code gen action.\n" |
| 140 " deps = [ \":foo_idl_files\" ]\n" |
82 " }\n"; | 141 " }\n"; |
83 | 142 |
84 Value RunTemplate(Scope* scope, | 143 Value RunTemplate(Scope* scope, |
85 const FunctionCallNode* function, | 144 const FunctionCallNode* function, |
86 const std::vector<Value>& args, | 145 const std::vector<Value>& args, |
87 BlockNode* block, | 146 BlockNode* block, |
88 Err* err) { | 147 Err* err) { |
89 // TODO(brettw) determine if the function is built-in and throw an error if | 148 // TODO(brettw) determine if the function is built-in and throw an error if |
90 // it is. | 149 // it is. |
91 if (args.size() != 1) { | 150 if (args.size() != 1) { |
92 *err = Err(function->function(), | 151 *err = Err(function->function(), |
93 "Need exactly one string arg to template."); | 152 "Need exactly one string arg to template."); |
94 return Value(); | 153 return Value(); |
95 } | 154 } |
96 if (!args[0].VerifyTypeIs(Value::STRING, err)) | 155 if (!args[0].VerifyTypeIs(Value::STRING, err)) |
97 return Value(); | 156 return Value(); |
98 std::string template_name = args[0].string_value(); | 157 std::string template_name = args[0].string_value(); |
99 | 158 |
100 const FunctionCallNode* existing_template = scope->GetTemplate(template_name); | 159 const Template* existing_template = scope->GetTemplate(template_name); |
101 if (existing_template) { | 160 if (existing_template) { |
102 *err = Err(function, "Duplicate template definition.", | 161 *err = Err(function, "Duplicate template definition.", |
103 "A template with this name was already defined."); | 162 "A template with this name was already defined."); |
104 err->AppendSubErr(Err(existing_template->function(), | 163 err->AppendSubErr(Err(existing_template->GetDefinitionRange(), |
105 "Previous definition.")); | 164 "Previous definition.")); |
106 return Value(); | 165 return Value(); |
107 } | 166 } |
108 | 167 |
109 scope->AddTemplate(template_name, function); | 168 scope->AddTemplate(template_name, |
| 169 scoped_ptr<Template>(new Template(scope, function))); |
110 return Value(); | 170 return Value(); |
111 } | 171 } |
112 | 172 |
113 } // namespace functions | 173 } // namespace functions |
OLD | NEW |