• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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