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.
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/value_extractors.h"
13 #include "tools/gn/variables.h"
19 // This is jsut a unique value to take the address of to use as the key for
20 // the toolchain property on a scope.
21 const int kToolchainPropertyKey = 0;
23 // Reads the given string from the scope (if present) and puts the result into
24 // dest. If the value is not a string, sets the error and returns false.
25 bool ReadString(Scope& scope, const char* var, std::string* dest, Err* err) {
26 const Value* v = scope.GetValue(var, true);
28 return true; // Not present is fine.
30 if (!v->VerifyTypeIs(Value::STRING, err))
32 *dest = v->string_value();
38 // toolchain -------------------------------------------------------------------
40 const char kToolchain[] = "toolchain";
41 const char kToolchain_HelpShort[] =
42 "toolchain: Defines a toolchain.";
43 const char kToolchain_Help[] =
44 "toolchain: Defines a toolchain.\n"
46 " A toolchain is a set of commands and build flags used to compile the\n"
47 " source code. You can have more than one toolchain in use at once in\n"
50 " A toolchain specifies the commands to run for various input file\n"
51 " types via the \"tool\" call (see \"gn help tool\") and specifies\n"
52 " arguments to be passed to the toolchain build via the\n"
53 " \"toolchain_args\" call (see \"gn help toolchain_args\").\n"
55 " In addition, a toolchain can specify dependencies via the \"deps\"\n"
56 " variable like a target. These dependencies will be resolved before any\n"
57 " target in the toolchain is compiled. To avoid circular dependencies\n"
58 " these must be targets defined in another toolchain.\n"
60 "Invoking targets in toolchains:\n"
62 " By default, when a target depends on another, there is an implicit\n"
63 " toolchain label that is inherited, so the dependee has the same one\n"
64 " as the dependent.\n"
66 " You can override this and refer to any other toolchain by explicitly\n"
67 " labeling the toolchain to use. For example:\n"
68 " datadeps = [ \"//plugins:mine(//toolchains:plugin_toolchain)\" ]\n"
69 " The string \"//build/toolchains:plugin_toolchain\" is a label that\n"
70 " identifies the toolchain declaration for compiling the sources.\n"
72 " To load a file in an alternate toolchain, GN does the following:\n"
74 " 1. Loads the file with the toolchain definition in it (as determined\n"
75 " by the toolchain label).\n"
76 " 2. Re-runs the master build configuration file, applying the\n"
77 " arguments specified by the toolchain_args section of the toolchain\n"
78 " definition (see \"gn help toolchain_args\").\n"
79 " 3. Loads the destination build file in the context of the\n"
80 " configuration file in the previous step.\n"
83 " toolchain(\"plugin_toolchain\") {\n"
85 " command = \"gcc $in\"\n"
88 " toolchain_args() {\n"
95 Value RunToolchain(Scope* scope,
96 const FunctionCallNode* function,
97 const std::vector<Value>& args,
100 if (!EnsureNotProcessingImport(function, scope, err) ||
101 !EnsureNotProcessingBuildConfig(function, scope, err))
104 // Note that we don't want to use MakeLabelForScope since that will include
105 // the toolchain name in the label, and toolchain labels don't themselves
106 // have toolchain names.
107 const SourceDir& input_dir = scope->GetSourceDir();
108 Label label(input_dir, args[0].string_value());
109 if (g_scheduler->verbose_logging())
110 g_scheduler->Log("Definining toolchain", label.GetUserVisibleName(false));
112 // This object will actually be copied into the one owned by the toolchain
113 // manager, but that has to be done in the lock.
114 scoped_ptr<Toolchain> toolchain(new Toolchain(scope->settings(), label));
115 toolchain->set_defined_from(function);
116 toolchain->visibility().SetPublic();
118 Scope block_scope(scope);
119 block_scope.SetProperty(&kToolchainPropertyKey, toolchain.get());
120 block->ExecuteBlockInScope(&block_scope, err);
121 block_scope.SetProperty(&kToolchainPropertyKey, NULL);
122 if (err->has_error())
125 // Read deps (if any).
126 const Value* deps_value = block_scope.GetValue(variables::kDeps, true);
129 *deps_value, block_scope.GetSourceDir(),
130 ToolchainLabelForScope(&block_scope), &toolchain->deps(), err);
131 if (err->has_error())
136 if (!block_scope.CheckForUnusedVars(err))
139 // Save this toolchain.
140 Scope::ItemVector* collector = scope->GetItemCollector();
142 *err = Err(function, "Can't define a toolchain in this context.");
145 collector->push_back(new scoped_ptr<Item>(toolchain.PassAs<Item>()));
149 // tool ------------------------------------------------------------------------
151 const char kTool[] = "tool";
152 const char kTool_HelpShort[] =
153 "tool: Specify arguments to a toolchain tool.";
154 const char kTool_Help[] =
155 "tool: Specify arguments to a toolchain tool.\n"
157 " tool(<command type>) { <command flags> }\n"
159 " Used inside a toolchain definition to define a command to run for a\n"
160 " given file type. See also \"gn help toolchain\".\n"
164 " The following values may be passed to the tool() function for the type\n"
167 " \"cc\", \"cxx\", \"objc\", \"objcxx\", \"asm\", \"alink\", \"solink\",\n"
168 " \"link\", \"stamp\", \"copy\"\n"
170 "Tool-specific notes\n"
173 " The copy command should be a native OS command since it does not\n"
174 " implement toolchain dependencies (which would enable a copy tool to\n"
175 " be compiled by a previous step).\n"
177 " It is legal for the copy to not update the timestamp of the output\n"
178 " file (as long as it's greater than or equal to the input file). This\n"
179 " allows the copy command to be implemented as a hard link which can\n"
180 " be more efficient.\n"
184 " These variables may be specified in the { } block after the tool call.\n"
185 " They are passed directly to Ninja. See the ninja documentation for how\n"
186 " they work. Don't forget to backslash-escape $ required by Ninja to\n"
187 " prevent GN from doing variable expansion.\n"
189 " command, depfile, depsformat, description, pool, restat, rspfile,\n"
192 " (Note that GN uses \"depsformat\" for Ninja's \"deps\" variable to\n"
193 " avoid confusion with dependency lists.)\n"
195 " Additionally, lib_prefix and lib_dir_prefix may be used for the link\n"
196 " tools. These strings will be prepended to the libraries and library\n"
197 " search directories, respectively, because linkers differ on how to\n"
200 " Note: On Mac libraries with names ending in \".framework\" will be\n"
201 " added to the link like with a \"-framework\" switch and the lib prefix\n"
202 " will be ignored.\n"
204 "Ninja variables available to tool invocations\n"
206 " When writing tool commands, you use the various built-in Ninja\n"
207 " variables like \"$in\" and \"$out\" (note that the $ must be escaped\n"
208 " for it to be passed to Ninja, so write \"\\$in\" in the command\n"
211 " GN defines the following variables for binary targets to access the\n"
212 " various computed information needed for compiling:\n"
214 " - Compiler flags: \"cflags\", \"cflags_c\", \"cflags_cc\",\n"
215 " \"cflags_objc\", \"cflags_objcc\"\n"
217 " - Linker flags: \"ldflags\", \"libs\"\n"
219 " GN sets these other variables with target information that can be\n"
220 " used for computing names for supplimetary files:\n"
222 " - \"target_name\": The name of the current target with no\n"
223 " path information. For example \"mylib\".\n"
225 " - \"target_out_dir\": The value of \"target_out_dir\" from the BUILD\n"
226 " file for this target (see \"gn help target_out_dir\"), relative\n"
227 " to the root build directory with no trailing slash.\n"
229 " - \"root_out_dir\": The value of \"root_out_dir\" from the BUILD\n"
230 " file for this target (see \"gn help root_out_dir\"), relative\n"
231 " to the root build directory with no trailing slash.\n"
235 " toolchain(\"my_toolchain\") {\n"
236 " # Put these at the top to apply to all tools below.\n"
237 " lib_prefix = \"-l\"\n"
238 " lib_dir_prefix = \"-L\"\n"
241 " command = \"gcc \\$in -o \\$out\"\n"
242 " description = \"GCC \\$in\"\n"
245 " command = \"g++ \\$in -o \\$out\"\n"
246 " description = \"G++ \\$in\"\n"
250 Value RunTool(Scope* scope,
251 const FunctionCallNode* function,
252 const std::vector<Value>& args,
255 // Find the toolchain definition we're executing inside of. The toolchain
256 // function will set a property pointing to it that we'll pick up.
257 Toolchain* toolchain = reinterpret_cast<Toolchain*>(
258 scope->GetProperty(&kToolchainPropertyKey, NULL));
260 *err = Err(function->function(), "tool() called outside of toolchain().",
261 "The tool() function can only be used inside a toolchain() "
266 if (!EnsureSingleStringArg(function, args, err))
268 const std::string& tool_name = args[0].string_value();
269 Toolchain::ToolType tool_type = Toolchain::ToolNameToType(tool_name);
270 if (tool_type == Toolchain::TYPE_NONE) {
271 *err = Err(args[0], "Unknown tool type");
275 // Run the tool block.
276 Scope block_scope(scope);
277 block->ExecuteBlockInScope(&block_scope, err);
278 if (err->has_error())
281 // Extract the stuff we need.
283 if (!ReadString(block_scope, "command", &t.command, err) ||
284 !ReadString(block_scope, "depfile", &t.depfile, err) ||
285 // TODO(brettw) delete this once we rename "deps" -> "depsformat" in
286 // the toolchain definitions. This will avoid colliding with the
287 // toolchain's "deps" list. For now, accept either.
288 !ReadString(block_scope, "deps", &t.depsformat, err) ||
289 !ReadString(block_scope, "depsformat", &t.depsformat, err) ||
290 !ReadString(block_scope, "description", &t.description, err) ||
291 !ReadString(block_scope, "lib_dir_prefix", &t.lib_dir_prefix, err) ||
292 !ReadString(block_scope, "lib_prefix", &t.lib_prefix, err) ||
293 !ReadString(block_scope, "pool", &t.pool, err) ||
294 !ReadString(block_scope, "restat", &t.restat, err) ||
295 !ReadString(block_scope, "rspfile", &t.rspfile, err) ||
296 !ReadString(block_scope, "rspfile_content", &t.rspfile_content, err))
299 // Make sure there weren't any vars set in this tool that were unused.
300 if (!block_scope.CheckForUnusedVars(err))
303 toolchain->SetTool(tool_type, t);
307 // toolchain_args --------------------------------------------------------------
309 extern const char kToolchainArgs[] = "toolchain_args";
310 extern const char kToolchainArgs_HelpShort[] =
311 "toolchain_args: Set build arguments for toolchain build setup.";
312 extern const char kToolchainArgs_Help[] =
313 "toolchain_args: Set build arguments for toolchain build setup.\n"
315 " Used inside a toolchain definition to pass arguments to an alternate\n"
316 " toolchain's invocation of the build.\n"
318 " When you specify a target using an alternate toolchain, the master\n"
319 " build configuration file is re-interpreted in the context of that\n"
320 " toolchain (see \"gn help toolchain\"). The toolchain_args function\n"
321 " allows you to control the arguments passed into this alternate\n"
322 " invocation of the build.\n"
324 " Any default system arguments or arguments passed in on the command-\n"
325 " line will also be passed to the alternate invocation unless explicitly\n"
326 " overridden by toolchain_args.\n"
328 " The toolchain_args will be ignored when the toolchain being defined\n"
329 " is the default. In this case, it's expected you want the default\n"
330 " argument values.\n"
332 " See also \"gn help buildargs\" for an overview of these arguments.\n"
335 " toolchain(\"my_weird_toolchain\") {\n"
337 " toolchain_args() {\n"
338 " # Override the system values for a generic Posix system.\n"
342 " # Pass this new value for specific setup for my toolchain.\n"
343 " is_my_weird_system = true\n"
347 Value RunToolchainArgs(Scope* scope,
348 const FunctionCallNode* function,
349 const std::vector<Value>& args,
352 // Find the toolchain definition we're executing inside of. The toolchain
353 // function will set a property pointing to it that we'll pick up.
354 Toolchain* toolchain = reinterpret_cast<Toolchain*>(
355 scope->GetProperty(&kToolchainPropertyKey, NULL));
357 *err = Err(function->function(),
358 "toolchain_args() called outside of toolchain().",
359 "The toolchain_args() function can only be used inside a "
360 "toolchain() definition.");
365 *err = Err(function->function(), "This function takes no arguments.");
369 // This function makes a new scope with various variable sets on it, which
370 // we then save on the toolchain to use when re-invoking the build.
371 Scope block_scope(scope);
372 block->ExecuteBlockInScope(&block_scope, err);
373 if (err->has_error())
376 Scope::KeyValueMap values;
377 block_scope.GetCurrentScopeValues(&values);
378 toolchain->args() = values;
383 } // namespace functions