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