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/err.h"
6 #include "tools/gn/functions.h"
7 #include "tools/gn/parse_tree.h"
8 #include "tools/gn/scheduler.h"
9 #include "tools/gn/scope.h"
10 #include "tools/gn/settings.h"
11 #include "tools/gn/toolchain.h"
12 #include "tools/gn/variables.h"
13
14 namespace functions {
15
16 namespace {
17
18 // This is jsut a unique value to take the address of to use as the key for
19 // the toolchain property on a scope.
20 const int kToolchainPropertyKey = 0;
21
22 // Reads the given string from the scope (if present) and puts the result into
23 // dest. If the value is not a string, sets the error and returns false.
ReadString(Scope & scope,const char * var,std::string * dest,Err * err)24 bool ReadString(Scope& scope, const char* var, std::string* dest, Err* err) {
25 const Value* v = scope.GetValue(var, true);
26 if (!v)
27 return true; // Not present is fine.
28
29 if (!v->VerifyTypeIs(Value::STRING, err))
30 return false;
31 *dest = v->string_value();
32 return true;
33 }
34
35 } // namespace
36
37 // toolchain -------------------------------------------------------------------
38
39 const char kToolchain[] = "toolchain";
40 const char kToolchain_Help[] =
41 "toolchain: Defines a toolchain.\n"
42 "\n"
43 " A toolchain is a set of commands and build flags used to compile the\n"
44 " source code. You can have more than one toolchain in use at once in\n"
45 " a build.\n"
46 "\n"
47 " A toolchain specifies the commands to run for various input file\n"
48 " types via the \"tool\" call (see \"gn help tool\") and specifies\n"
49 " arguments to be passed to the toolchain build via the\n"
50 " \"toolchain_args\" call (see \"gn help toolchain_args\").\n"
51 "\n"
52 "Invoking targets in toolchains:\n"
53 "\n"
54 " By default, when a target depends on another, there is an implicit\n"
55 " toolchain label that is inherited, so the dependee has the same one\n"
56 " as the dependant.\n"
57 "\n"
58 " You can override this and refer to any other toolchain by explicitly\n"
59 " labeling the toolchain to use. For example:\n"
60 " datadeps = [ \"//plugins:mine(//toolchains:plugin_toolchain)\" ]\n"
61 " The string \"//build/toolchains:plugin_toolchain\" is a label that\n"
62 " identifies the toolchain declaration for compiling the sources.\n"
63 "\n"
64 " To load a file in an alternate toolchain, GN does the following:\n"
65 "\n"
66 " 1. Loads the file with the toolchain definition in it (as determined\n"
67 " by the toolchain label).\n"
68 " 2. Re-runs the master build configuration file, applying the\n"
69 " arguments specified by the toolchain_args section of the toolchain\n"
70 " definition (see \"gn help toolchain_args\").\n"
71 " 3. Loads the destination build file in the context of the\n"
72 " configuration file in the previous step.\n"
73 "\n"
74 "Example:\n"
75 " toolchain(\"plugin_toolchain\") {\n"
76 " tool(\"cc\") {\n"
77 " command = \"gcc $in\""
78 " }\n"
79 "\n"
80 " toolchain_args() {\n"
81 " is_plugin = true\n"
82 " is_32bit = true\n"
83 " is_64bit = false\n"
84 " }\n"
85 " }\n";
86
RunToolchain(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)87 Value RunToolchain(Scope* scope,
88 const FunctionCallNode* function,
89 const std::vector<Value>& args,
90 BlockNode* block,
91 Err* err) {
92 if (!EnsureNotProcessingImport(function, scope, err) ||
93 !EnsureNotProcessingBuildConfig(function, scope, err))
94 return Value();
95
96 // Note that we don't want to use MakeLabelForScope since that will include
97 // the toolchain name in the label, and toolchain labels don't themselves
98 // have toolchain names.
99 const SourceDir& input_dir = scope->GetSourceDir();
100 Label label(input_dir, args[0].string_value());
101 if (g_scheduler->verbose_logging())
102 g_scheduler->Log("Definining toolchain", label.GetUserVisibleName(false));
103
104 // This object will actually be copied into the one owned by the toolchain
105 // manager, but that has to be done in the lock.
106 scoped_ptr<Toolchain> toolchain(new Toolchain(scope->settings(), label));
107 toolchain->set_defined_from(function);
108
109 Scope block_scope(scope);
110 block_scope.SetProperty(&kToolchainPropertyKey, toolchain.get());
111 block->ExecuteBlockInScope(&block_scope, err);
112 block_scope.SetProperty(&kToolchainPropertyKey, NULL);
113 if (err->has_error())
114 return Value();
115
116 // Extract the gyp_header contents, if any.
117 const Value* gyp_header_value =
118 block_scope.GetValue(variables::kGypHeader, true);
119 if (gyp_header_value) {
120 if (!gyp_header_value->VerifyTypeIs(Value::STRING, err))
121 return Value();
122 toolchain->set_gyp_header(gyp_header_value->string_value());
123 }
124
125 if (!block_scope.CheckForUnusedVars(err))
126 return Value();
127
128 scope->settings()->build_settings()->ItemDefined(toolchain.PassAs<Item>());
129 return Value();
130 }
131
132 // tool ------------------------------------------------------------------------
133
134 const char kTool[] = "tool";
135 const char kTool_Help[] =
136 "tool: Specify arguments to a toolchain tool.\n"
137 "\n"
138 " tool(<command type>) { <command flags> }\n"
139 "\n"
140 " Used inside a toolchain definition to define a command to run for a\n"
141 " given file type. See also \"gn help toolchain\".\n"
142 "\n"
143 "Command types:\n"
144 " The following values may be passed to the tool() function for the type\n"
145 " of the command:\n"
146 "\n"
147 " \"cc\", \"cxx\", \"objc\", \"objcxx\", \"asm\", \"alink\", \"solink\",\n"
148 " \"link\", \"stamp\", \"copy\"\n"
149 "\n"
150 "Command flags:\n"
151 "\n"
152 " These variables may be specified in the { } block after the tool call.\n"
153 " They are passed directly to Ninja. See the ninja documentation for how\n"
154 " they work. Don't forget to backslash-escape $ required by Ninja to\n"
155 " prevent GN from doing variable expansion.\n"
156 "\n"
157 " command, depfile, deps, description, pool, restat, rspfile,\n"
158 " rspfile_content\n"
159 "\n"
160 " Additionally, lib_prefix and lib_dir_prefix may be used for the link\n"
161 " tools. These strings will be prepended to the libraries and library\n"
162 " search directories, respectively, because linkers differ on how to\n"
163 " specify them.\n"
164 "\n"
165 " Note: On Mac libraries with names ending in \".framework\" will be\n"
166 " added to the link like with a \"-framework\" switch and the lib prefix\n"
167 " will be ignored.\n"
168 "\n"
169 "Example:\n"
170 " toolchain(\"my_toolchain\") {\n"
171 " # Put these at the top to apply to all tools below.\n"
172 " lib_prefix = \"-l\"\n"
173 " lib_dir_prefix = \"-L\"\n"
174 "\n"
175 " tool(\"cc\") {\n"
176 " command = \"gcc \\$in -o \\$out\"\n"
177 " description = \"GCC \\$in\"\n"
178 " }\n"
179 " tool(\"cxx\") {\n"
180 " command = \"g++ \\$in -o \\$out\"\n"
181 " description = \"G++ \\$in\"\n"
182 " }\n"
183 " }\n";
184
RunTool(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)185 Value RunTool(Scope* scope,
186 const FunctionCallNode* function,
187 const std::vector<Value>& args,
188 BlockNode* block,
189 Err* err) {
190 // Find the toolchain definition we're executing inside of. The toolchain
191 // function will set a property pointing to it that we'll pick up.
192 Toolchain* toolchain = reinterpret_cast<Toolchain*>(
193 scope->GetProperty(&kToolchainPropertyKey, NULL));
194 if (!toolchain) {
195 *err = Err(function->function(), "tool() called outside of toolchain().",
196 "The tool() function can only be used inside a toolchain() "
197 "definition.");
198 return Value();
199 }
200
201 if (!EnsureSingleStringArg(function, args, err))
202 return Value();
203 const std::string& tool_name = args[0].string_value();
204 Toolchain::ToolType tool_type = Toolchain::ToolNameToType(tool_name);
205 if (tool_type == Toolchain::TYPE_NONE) {
206 *err = Err(args[0], "Unknown tool type");
207 return Value();
208 }
209
210 // Run the tool block.
211 Scope block_scope(scope);
212 block->ExecuteBlockInScope(&block_scope, err);
213 if (err->has_error())
214 return Value();
215
216 // Extract the stuff we need.
217 Toolchain::Tool t;
218 if (!ReadString(block_scope, "command", &t.command, err) ||
219 !ReadString(block_scope, "depfile", &t.depfile, err) ||
220 !ReadString(block_scope, "deps", &t.deps, err) ||
221 !ReadString(block_scope, "description", &t.description, err) ||
222 !ReadString(block_scope, "lib_dir_prefix", &t.lib_dir_prefix, err) ||
223 !ReadString(block_scope, "lib_prefix", &t.lib_prefix, err) ||
224 !ReadString(block_scope, "pool", &t.pool, err) ||
225 !ReadString(block_scope, "restat", &t.restat, err) ||
226 !ReadString(block_scope, "rspfile", &t.rspfile, err) ||
227 !ReadString(block_scope, "rspfile_content", &t.rspfile_content, err))
228 return Value();
229
230 // Make sure there weren't any vars set in this tool that were unused.
231 if (!block_scope.CheckForUnusedVars(err))
232 return Value();
233
234 toolchain->SetTool(tool_type, t);
235 return Value();
236 }
237
238 // toolchain_args --------------------------------------------------------------
239
240 extern const char kToolchainArgs[] = "toolchain_args";
241 extern const char kToolchainArgs_Help[] =
242 "toolchain_args: Set build arguments for toolchain build setup.\n"
243 "\n"
244 " Used inside a toolchain definition to pass arguments to an alternate\n"
245 " toolchain's invocation of the build.\n"
246 "\n"
247 " When you specify a target using an alternate toolchain, the master\n"
248 " build configuration file is re-interpreted in the context of that\n"
249 " toolchain (see \"gn help toolchain\"). The toolchain_args function\n"
250 " allows you to control the arguments passed into this alternate\n"
251 " invocation of the build.\n"
252 "\n"
253 " Any default system arguments or arguments passed in on the command-\n"
254 " line will also be passed to the alternate invocation unless explicitly\n"
255 " overridden by toolchain_args.\n"
256 "\n"
257 " The toolchain_args will be ignored when the toolchain being defined\n"
258 " is the default. In this case, it's expected you want the default\n"
259 " argument values.\n"
260 "\n"
261 " See also \"gn help buildargs\" for an overview of these arguments.\n"
262 "\n"
263 "Example:\n"
264 " toolchain(\"my_weird_toolchain\") {\n"
265 " ...\n"
266 " toolchain_args() {\n"
267 " # Override the system values for a generic Posix system.\n"
268 " is_win = false\n"
269 " is_posix = true\n"
270 "\n"
271 " # Pass this new value for specific setup for my toolchain.\n"
272 " is_my_weird_system = true\n"
273 " }\n"
274 " }\n";
275
RunToolchainArgs(Scope * scope,const FunctionCallNode * function,const std::vector<Value> & args,BlockNode * block,Err * err)276 Value RunToolchainArgs(Scope* scope,
277 const FunctionCallNode* function,
278 const std::vector<Value>& args,
279 BlockNode* block,
280 Err* err) {
281 // Find the toolchain definition we're executing inside of. The toolchain
282 // function will set a property pointing to it that we'll pick up.
283 Toolchain* toolchain = reinterpret_cast<Toolchain*>(
284 scope->GetProperty(&kToolchainPropertyKey, NULL));
285 if (!toolchain) {
286 *err = Err(function->function(),
287 "toolchain_args() called outside of toolchain().",
288 "The toolchain_args() function can only be used inside a "
289 "toolchain() definition.");
290 return Value();
291 }
292
293 if (!args.empty()) {
294 *err = Err(function->function(), "This function takes no arguments.");
295 return Value();
296 }
297
298 // This function makes a new scope with various variable sets on it, which
299 // we then save on the toolchain to use when re-invoking the build.
300 Scope block_scope(scope);
301 block->ExecuteBlockInScope(&block_scope, err);
302 if (err->has_error())
303 return Value();
304
305 Scope::KeyValueMap values;
306 block_scope.GetCurrentScopeValues(&values);
307 toolchain->args() = values;
308
309 return Value();
310 }
311
312 } // namespace functions
313