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 <algorithm> | |
6 | |
5 #include "tools/gn/err.h" | 7 #include "tools/gn/err.h" |
6 #include "tools/gn/functions.h" | 8 #include "tools/gn/functions.h" |
7 #include "tools/gn/parse_tree.h" | 9 #include "tools/gn/parse_tree.h" |
8 #include "tools/gn/scheduler.h" | 10 #include "tools/gn/scheduler.h" |
9 #include "tools/gn/scope.h" | 11 #include "tools/gn/scope.h" |
10 #include "tools/gn/settings.h" | 12 #include "tools/gn/settings.h" |
13 #include "tools/gn/tool.h" | |
11 #include "tools/gn/toolchain.h" | 14 #include "tools/gn/toolchain.h" |
12 #include "tools/gn/value_extractors.h" | 15 #include "tools/gn/value_extractors.h" |
13 #include "tools/gn/variables.h" | 16 #include "tools/gn/variables.h" |
14 | 17 |
15 namespace functions { | 18 namespace functions { |
16 | 19 |
17 namespace { | 20 namespace { |
18 | 21 |
19 // This is jsut a unique value to take the address of to use as the key for | 22 // This is jsut a unique value to take the address of to use as the key for |
20 // the toolchain property on a scope. | 23 // the toolchain property on a scope. |
21 const int kToolchainPropertyKey = 0; | 24 const int kToolchainPropertyKey = 0; |
22 | 25 |
26 bool ReadBool(Scope* scope, | |
27 const char* var, | |
28 Tool* tool, | |
29 void (Tool::*set)(bool), | |
30 Err* err) { | |
31 const Value* v = scope->GetValue(var, true); | |
32 if (!v) | |
33 return true; // Not present is fine. | |
34 if (!v->VerifyTypeIs(Value::BOOLEAN, err)) | |
35 return false; | |
36 | |
37 (tool->*set)(v->boolean_value()); | |
38 return true; | |
39 } | |
40 | |
23 // Reads the given string from the scope (if present) and puts the result into | 41 // 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. | 42 // 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) { | 43 bool ReadString(Scope* scope, |
26 const Value* v = scope.GetValue(var, true); | 44 const char* var, |
45 Tool* tool, | |
46 void (Tool::*set)(const std::string&), | |
47 Err* err) { | |
48 const Value* v = scope->GetValue(var, true); | |
27 if (!v) | 49 if (!v) |
28 return true; // Not present is fine. | 50 return true; // Not present is fine. |
29 | |
30 if (!v->VerifyTypeIs(Value::STRING, err)) | 51 if (!v->VerifyTypeIs(Value::STRING, err)) |
31 return false; | 52 return false; |
32 *dest = v->string_value(); | 53 |
54 (tool->*set)(v->string_value()); | |
33 return true; | 55 return true; |
34 } | 56 } |
35 | 57 |
58 // Calls the given validate function on each type in the list. On failure, | |
59 // sets the error, blame the value, and return false. | |
60 bool ValidateSubstitutionList(const std::vector<SubstitutionType>& list, | |
61 bool (*validate)(SubstitutionType), | |
62 const Value* origin, | |
63 Err* err) { | |
64 for (size_t i = 0; i < list.size(); i++) { | |
65 SubstitutionType cur_type = list[i]; | |
66 if (!validate(cur_type)) { | |
67 *err = Err(*origin, "Pattern not valid here.", | |
68 "You used the pattern " + std::string(kSubstitutionNames[cur_type]) + | |
69 " which is not valid\nfor this variable."); | |
70 return false; | |
71 } | |
72 } | |
73 return true; | |
74 } | |
75 | |
76 bool ReadPattern(Scope* scope, | |
77 const char* name, | |
78 bool (*validate)(SubstitutionType), | |
79 Tool* tool, | |
80 void (Tool::*set)(const SubstitutionPattern&), | |
81 Err* err) { | |
82 const Value* value = scope->GetValue(name, true); | |
83 if (!value) | |
84 return true; // Not present is fine. | |
85 if (!value->VerifyTypeIs(Value::STRING, err)) | |
86 return false; | |
87 | |
88 SubstitutionPattern pattern; | |
89 if (!pattern.Parse(*value, err)) | |
90 return false; | |
91 if (!ValidateSubstitutionList(pattern.required_types(), validate, value, err)) | |
92 return false; | |
93 | |
94 (tool->*set)(pattern); | |
95 return true; | |
96 } | |
97 | |
98 bool ReadOutputExtension(Scope* scope, Tool* tool, Err* err) { | |
99 const Value* value = scope->GetValue("default_output_extension", true); | |
100 if (!value) | |
101 return true; // Not present is fine. | |
102 if (!value->VerifyTypeIs(Value::STRING, err)) | |
103 return false; | |
104 | |
105 if (value->string_value().empty()) | |
106 return true; // Accept empty string. | |
107 | |
108 if (value->string_value()[0] != '.') { | |
109 *err = Err(*value, "default_output_extension must begin with a '.'"); | |
110 return false; | |
111 } | |
112 | |
113 tool->set_default_output_extension(value->string_value()); | |
114 return true; | |
115 } | |
116 | |
117 bool ReadDepsFormat(Scope* scope, Tool* tool, Err* err) { | |
118 const Value* value = scope->GetValue("depsformat", true); | |
119 if (!value) | |
120 return true; // Not present is fine. | |
121 if (!value->VerifyTypeIs(Value::STRING, err)) | |
122 return false; | |
123 | |
124 if (value->string_value() == "gcc") { | |
125 tool->set_depsformat(Tool::DEPS_GCC); | |
126 } else if (value->string_value() == "msvc") { | |
127 tool->set_depsformat(Tool::DEPS_MSVC); | |
128 } else { | |
129 *err = Err(*value, "Deps format must be \"gcc\" or \"msvc\"."); | |
130 return false; | |
131 } | |
132 return true; | |
133 } | |
134 | |
135 bool ReadOutputs(Scope* scope, | |
136 const FunctionCallNode* tool_function, | |
137 bool (*validate)(SubstitutionType), | |
138 Tool* tool, | |
139 Err* err) { | |
140 const Value* value = scope->GetValue("outputs", true); | |
141 if (!value) { | |
142 *err = Err(tool_function, "\"outputs\" must be specified for this tool."); | |
143 return false; | |
144 } | |
145 | |
146 SubstitutionList list; | |
147 if (!list.Parse(*value, err)) | |
148 return false; | |
149 | |
150 // Validate the right kinds of patterns are used. | |
151 if (!ValidateSubstitutionList(list.required_types(), validate, value, err)) | |
152 return false; | |
153 | |
154 // There should always be at least one output. | |
155 if (list.list().empty()) { | |
156 *err = Err(*value, "Outputs list is empty.", "I need some outputs."); | |
157 return false; | |
158 } | |
159 | |
160 // Each output should be in the output directory. | |
161 /* | |
jamesr
2014/08/19 19:30:41
?
brettw
2014/08/19 21:29:56
Deleted
| |
162 for (size_t i = 0; i < list.list().size(); i++) { | |
163 if (!list.list()[i].IsInOutputDir(scope->settings()->build_settings(), err)) | |
164 return false; | |
165 } | |
166 */ | |
167 | |
168 tool->set_outputs(list); | |
169 return true; | |
170 } | |
171 | |
172 bool IsCompilerTool(Toolchain::ToolType type) { | |
173 return type == Toolchain::TYPE_CC || | |
174 type == Toolchain::TYPE_CXX || | |
175 type == Toolchain::TYPE_OBJC || | |
176 type == Toolchain::TYPE_OBJCXX || | |
177 type == Toolchain::TYPE_RC || | |
178 type == Toolchain::TYPE_ASM; | |
179 } | |
180 | |
181 bool IsLinkerTool(Toolchain::ToolType type) { | |
182 return type == Toolchain::TYPE_ALINK || | |
183 type == Toolchain::TYPE_SOLINK || | |
184 type == Toolchain::TYPE_LINK; | |
185 } | |
186 | |
187 bool IsPatternInOutputList(const SubstitutionList& output_list, | |
188 const SubstitutionPattern& pattern) { | |
189 for (size_t output_i = 0; output_i < output_list.list().size(); output_i++) { | |
190 const SubstitutionPattern& cur = output_list.list()[output_i]; | |
191 if (pattern.ranges().size() == cur.ranges().size() && | |
192 std::equal(pattern.ranges().begin(), pattern.ranges().end(), | |
193 cur.ranges().begin())) | |
194 return true; | |
195 } | |
196 return false; | |
197 } | |
198 | |
36 } // namespace | 199 } // namespace |
37 | 200 |
38 // toolchain ------------------------------------------------------------------- | 201 // toolchain ------------------------------------------------------------------- |
39 | 202 |
40 const char kToolchain[] = "toolchain"; | 203 const char kToolchain[] = "toolchain"; |
41 const char kToolchain_HelpShort[] = | 204 const char kToolchain_HelpShort[] = |
42 "toolchain: Defines a toolchain."; | 205 "toolchain: Defines a toolchain."; |
43 const char kToolchain_Help[] = | 206 const char kToolchain_Help[] = |
44 "toolchain: Defines a toolchain.\n" | 207 "toolchain: Defines a toolchain.\n" |
45 "\n" | 208 "\n" |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
125 // Read deps (if any). | 288 // Read deps (if any). |
126 const Value* deps_value = block_scope.GetValue(variables::kDeps, true); | 289 const Value* deps_value = block_scope.GetValue(variables::kDeps, true); |
127 if (deps_value) { | 290 if (deps_value) { |
128 ExtractListOfLabels( | 291 ExtractListOfLabels( |
129 *deps_value, block_scope.GetSourceDir(), | 292 *deps_value, block_scope.GetSourceDir(), |
130 ToolchainLabelForScope(&block_scope), &toolchain->deps(), err); | 293 ToolchainLabelForScope(&block_scope), &toolchain->deps(), err); |
131 if (err->has_error()) | 294 if (err->has_error()) |
132 return Value(); | 295 return Value(); |
133 } | 296 } |
134 | 297 |
135 | |
136 if (!block_scope.CheckForUnusedVars(err)) | 298 if (!block_scope.CheckForUnusedVars(err)) |
137 return Value(); | 299 return Value(); |
138 | 300 |
139 // Save this toolchain. | 301 // Save this toolchain. |
302 toolchain->ToolchainSetupComplete(); | |
140 Scope::ItemVector* collector = scope->GetItemCollector(); | 303 Scope::ItemVector* collector = scope->GetItemCollector(); |
141 if (!collector) { | 304 if (!collector) { |
142 *err = Err(function, "Can't define a toolchain in this context."); | 305 *err = Err(function, "Can't define a toolchain in this context."); |
143 return Value(); | 306 return Value(); |
144 } | 307 } |
145 collector->push_back(new scoped_ptr<Item>(toolchain.PassAs<Item>())); | 308 collector->push_back(new scoped_ptr<Item>(toolchain.PassAs<Item>())); |
146 return Value(); | 309 return Value(); |
147 } | 310 } |
148 | 311 |
149 // tool ------------------------------------------------------------------------ | 312 // tool ------------------------------------------------------------------------ |
150 | 313 |
151 const char kTool[] = "tool"; | 314 const char kTool[] = "tool"; |
152 const char kTool_HelpShort[] = | 315 const char kTool_HelpShort[] = |
153 "tool: Specify arguments to a toolchain tool."; | 316 "tool: Specify arguments to a toolchain tool."; |
154 const char kTool_Help[] = | 317 const char kTool_Help[] = |
155 "tool: Specify arguments to a toolchain tool.\n" | 318 "tool: Specify arguments to a toolchain tool.\n" |
156 "\n" | 319 "\n" |
157 " tool(<command type>) { <command flags> }\n" | 320 "Usage:\n" |
158 "\n" | 321 "\n" |
159 " Used inside a toolchain definition to define a command to run for a\n" | 322 " tool(<tool type>) {\n" |
160 " given file type. See also \"gn help toolchain\".\n" | 323 " <tool variables...>\n" |
161 "\n" | 324 " }\n" |
162 "Command types\n" | 325 "\n" |
163 "\n" | 326 "Tool types\n" |
164 " The following values may be passed to the tool() function for the type\n" | 327 "\n" |
165 " of the command:\n" | 328 " Compiler tools:\n" |
166 "\n" | 329 " \"cc\": C compiler\n" |
167 " \"cc\", \"cxx\", \"objc\", \"objcxx\", \"asm\", \"alink\", \"solink\",\n" | 330 " \"cxx\": C++ compiler\n" |
168 " \"link\", \"stamp\", \"copy\"\n" | 331 " \"objc\": Objective C compiler\n" |
169 "\n" | 332 " \"objcxx\": Objective C++ compiler\n" |
170 "Tool-specific notes\n" | 333 " \"rc\": Resource compiler (Windows .rc files)\n" |
171 "\n" | 334 " \"asm\": Assembler\n" |
172 " copy\n" | 335 "\n" |
173 " The copy command should be a native OS command since it does not\n" | 336 " Linker tools:\n" |
174 " implement toolchain dependencies (which would enable a copy tool to\n" | 337 " \"alink\": Linker for static libraries (archives)\n" |
175 " be compiled by a previous step).\n" | 338 " \"solink\": Linker for shared libraries\n" |
176 "\n" | 339 " \"link\": Linker for executables\n" |
177 " It is legal for the copy to not update the timestamp of the output\n" | 340 "\n" |
178 " file (as long as it's greater than or equal to the input file). This\n" | 341 " Other tools:\n" |
179 " allows the copy command to be implemented as a hard link which can\n" | 342 " \"stamp\": Tool for creating stamp files\n" |
180 " be more efficient.\n" | 343 " \"copy\": Tool to copy files.\n" |
181 "\n" | 344 "\n" |
182 "Command flags\n" | 345 "Tool variables\n" |
183 "\n" | 346 "\n" |
184 " These variables may be specified in the { } block after the tool call.\n" | 347 " command [string with substitutions]\n" |
185 " They are passed directly to Ninja. See the ninja documentation for how\n" | 348 " Valid for: all tools (required)\n" |
186 " they work. Don't forget to backslash-escape $ required by Ninja to\n" | 349 "\n" |
187 " prevent GN from doing variable expansion.\n" | 350 " The command to run.\n" |
188 "\n" | 351 "\n" |
189 " command, depfile, depsformat, description, pool, restat, rspfile,\n" | 352 " default_output_extension [string]\n" |
190 " rspfile_content\n" | 353 " Valid for: linker tools (required)\n" |
jamesr
2014/08/19 19:30:41
this says 'required' but the code allows it to be
| |
191 "\n" | 354 "\n" |
192 " (Note that GN uses \"depsformat\" for Ninja's \"deps\" variable to\n" | 355 " Extension for the main output of a linkable tool. It includes\n" |
193 " avoid confusion with dependency lists.)\n" | 356 " the leading dot. This will be the default value for the\n" |
194 "\n" | 357 " {{output_extension}} expansion (discussed below) but will be\n" |
195 " Additionally, lib_prefix and lib_dir_prefix may be used for the link\n" | 358 " overridden by by the \"output extension\" variable in a target,\n" |
196 " tools. These strings will be prepended to the libraries and library\n" | 359 " if one is specified. Empty string means no extension.\n" |
197 " search directories, respectively, because linkers differ on how to\n" | 360 "\n" |
198 " specify them.\n" | 361 " GN doesn't actually do anything with this extension other than\n" |
199 "\n" | 362 " pass it along, potentially with target-specific overrides. One\n" |
200 " Note: On Mac libraries with names ending in \".framework\" will be\n" | 363 " would typically use the {{output_extension}} value in the\n" |
201 " added to the link like with a \"-framework\" switch and the lib prefix\n" | 364 " \"outputs\" to read this value.\n" |
202 " will be ignored.\n" | 365 "\n" |
203 "\n" | 366 " Example: default_output_extension = \".exe\"\n" |
204 "Ninja variables available to tool invocations\n" | 367 "\n" |
205 "\n" | 368 " depfile [string]\n" |
206 " When writing tool commands, you use the various built-in Ninja\n" | 369 " Valid for: compiler tools (optional)\n" |
207 " variables like \"$in\" and \"$out\" (note that the $ must be escaped\n" | 370 "\n" |
208 " for it to be passed to Ninja, so write \"\\$in\" in the command\n" | 371 " If the tool can write \".d\" files, this specifies the name of\n" |
209 " string).\n" | 372 " the resulting file. These files are used to list header file\n" |
210 "\n" | 373 " dependencies (or other implicit input dependencies) that are\n" |
211 " GN defines the following variables for binary targets to access the\n" | 374 " discovered at build time. See also \"depsformat\".\n" |
212 " various computed information needed for compiling:\n" | 375 "\n" |
213 "\n" | 376 " Example: depfile = \"{{output}}.d\"\n" |
214 " - Compiler flags: \"cflags\", \"cflags_c\", \"cflags_cc\",\n" | 377 "\n" |
215 " \"cflags_objc\", \"cflags_objcc\"\n" | 378 " depsformat [string]\n" |
216 "\n" | 379 " Valid for: compiler tools (when depfile is specified)\n" |
217 " - Linker flags: \"ldflags\", \"libs\"\n" | 380 "\n" |
218 "\n" | 381 " Format for the deps outputs. This is either \"gcc\" or \"msvc\".\n" |
219 " GN sets these other variables with target information that can be\n" | 382 " See the ninja documentation for \"deps\" for more information.\n" |
220 " used for computing names for supplimetary files:\n" | 383 "\n" |
221 "\n" | 384 " Example: depsformat = \"gcc\"\n" |
222 " - \"target_name\": The name of the current target with no\n" | 385 "\n" |
223 " path information. For example \"mylib\".\n" | 386 " description [string with substitutions, optional]\n" |
224 "\n" | 387 " Valid for: all tools\n" |
225 " - \"target_out_dir\": The value of \"target_out_dir\" from the BUILD\n" | 388 "\n" |
226 " file for this target (see \"gn help target_out_dir\"), relative\n" | 389 " What to print when the command is run.\n" |
227 " to the root build directory with no trailing slash.\n" | 390 "\n" |
228 "\n" | 391 " Example: description = \"Compiling {{source}}\"\n" |
229 " - \"root_out_dir\": The value of \"root_out_dir\" from the BUILD\n" | 392 "\n" |
230 " file for this target (see \"gn help root_out_dir\"), relative\n" | 393 " lib_switch [string, optional, link tools only]\n" |
231 " to the root build directory with no trailing slash.\n" | 394 " lib_dir_switch [string, optional, link tools only]\n" |
395 " Valid for: Linker tools except \"alink\"\n" | |
396 "\n" | |
397 " These strings will be prepended to the libraries and library\n" | |
398 " search directories, respectively, because linkers differ on how\n" | |
399 " specify them. If you specified:\n" | |
400 " lib_switch = \"-l\"\n" | |
401 " lib_dir_switch = \"-L\"\n" | |
402 " then the \"{{libs}}\" expansion for [ \"freetype\", \"expat\"]\n" | |
403 " would be \"-lfreetype -lexpat\".\n" | |
404 "\n" | |
405 " outputs [list of strings with substitutions]\n" | |
406 " Valid for: Linker and compiler tools (required)\n" | |
407 "\n" | |
408 " An array of names for the output files the tool produces. These\n" | |
409 " are relative to the build output directory. There must always be\n" | |
410 " at least one output file. There can be more than one output (a\n" | |
411 " linker might produce a library and an import library, for\n" | |
412 " example).\n" | |
413 "\n" | |
414 " This array just declares to GN what files the tool will\n" | |
415 " produce. It is your responsibility to specify the tool command\n" | |
416 " that actually produces these files.\n" | |
417 "\n" | |
418 " If you specify more than one output for shared library links,\n" | |
419 " you should consider setting link_output and depend_output.\n" | |
420 " Otherwise, the first entry in the outputs list should always be\n" | |
421 " the main output which will be linked to.\n" | |
422 "\n" | |
423 " Example for a compiler tool that produces .obj files:\n" | |
424 " outputs = [\n" | |
425 " \"{{source_out_dir}}/{{source_name_part}}.obj\"\n" | |
426 " ]\n" | |
427 "\n" | |
428 " Example for a linker tool that produces a .dll and a .lib. The\n" | |
429 " use of {{output_extension}} rather than hardcoding \".dll\"\n" | |
430 " allows the extension of the library to be overridden on a\n" | |
431 " target-by-target basis, but in this example, it always\n" | |
432 " produces a \".lib\" import library:\n" | |
433 " outputs = [\n" | |
434 " \"{{root_out_dir}}/{{target_output_name}}" | |
435 "{{output_extension}}\",\n" | |
436 " \"{{root_out_dir}}/{{target_output_name}}.lib\",\n" | |
437 " ]\n" | |
438 "\n" | |
439 " link_output [string with substitutions]\n" | |
440 " depend_output [string with substitutions]\n" | |
441 " Valid for: \"solink\" only (optional)\n" | |
442 "\n" | |
443 " These two files specify whch of the outputs from the solink\n" | |
444 " tool should be used for linking and dependency tracking. These\n" | |
445 " should match entries in the \"outputs\". If unspecified, the\n" | |
446 " first item in the \"outputs\" array will be used for both. See\n" | |
447 " \"Separate linking and dependencies for shared libraries\"\n" | |
448 " below for more.\n" | |
449 "\n" | |
450 " On Windows, where the tools produce a .dll shared library and\n" | |
451 " a .lib import library, you will want both of these to be the\n" | |
452 " import library. On Linux, if you're not doing the separate\n" | |
453 " linking/dependency optimization, both of these should be the\n" | |
454 " .so output.\n" | |
455 "\n" | |
456 " output_prefix [string]\n" | |
457 " Valid for: Linker tools (optional)\n" | |
458 "\n" | |
459 " Prefix to use for the output name. Defaults to empty. This\n" | |
460 " prefix will be prepended to the name of the target (or the\n" | |
461 " output_name if one is manually specified for it) if the prefix\n" | |
462 " is not already there. The result will show up in the\n" | |
463 " {{output_name}} substitution pattern.\n" | |
464 "\n" | |
465 " This is typically used to prepend \"lib\" to libraries on\n" | |
466 " Posix systems:\n" | |
467 " output_prefix = \"lib\"\n" | |
468 "\n" | |
469 " pool [string, optional]\n" | |
470 " See the Ninja documentation.\n" | |
471 " TODO(brettw) write this. Probably doesn't work yet.\n" | |
jamesr
2014/08/19 19:30:41
should we just leave this out?
| |
472 "\n" | |
473 " restat [boolean]\n" | |
474 " Valid for: all tools (optional, defaults to false)\n" | |
475 "\n" | |
476 " Requests that Ninja check the file timestamp after this tool has\n" | |
477 " run to determine if anything changed. Set this if your tool has\n" | |
478 " the ability to skip writing output if the output file has not\n" | |
479 " changed.\n" | |
480 "\n" | |
481 " Normally, Ninja will assume that when a tool runs the output\n" | |
482 " be new and downstream dependents must be rebuild. When this is\n" | |
483 " set to trye, Ninja can skip rebuilding downstream dependents for\n" | |
484 " input changes that don't actually affect the output.\n" | |
485 "\n" | |
486 " Example:\n" | |
487 " restat = true\n" | |
488 "\n" | |
489 " rspfile [string with substitutions]\n" | |
490 " Valid for: all tools (optional)\n" | |
491 "\n" | |
492 " Name of the response file. If empty, no response file will be\n" | |
493 " used. See \"rspfile_content\".\n" | |
494 "\n" | |
495 " rspfile_content [string with substitutions]\n" | |
496 " Valid for: all tools (required when \"rspfile\" is specified)\n" | |
497 "\n" | |
498 " The contents to be written to the response file. This may\n" | |
499 " include all or part of the command to send to the tool which\n" | |
500 " allows you to get around OS command-line length limits.\n" | |
501 "\n" | |
502 " This example adds the inputs and libraries to a response file,\n" | |
503 " but passes the linker flags directly on the command line:\n" | |
504 " tool(\"link\") {\n" | |
505 " command = \"link -o {{output}} {{ldflags}} @{{output}}.rsp\"\n" | |
506 " rspfile = \"{{output}}.rsp\"\n" | |
507 " rspfile_content = \"{{inputs}} {{solibs}} {{libs}}\"\n" | |
508 " }\n" | |
509 "\n" | |
510 "Expansions for tool variables" | |
511 "\n" | |
512 " All paths are relative to the root build directory, which is the\n" | |
513 " current directory for running all tools. These expansions are\n" | |
514 " available to all tools:\n" | |
515 "\n" | |
516 " {{label}}\n" | |
517 " The label of the current target. This is typically used in the\n" | |
518 " \"description\" field for link tools. The toolchain will be\n" | |
519 " omitted from the label for targets in the default toolchain, and\n" | |
520 " will be included for targets in other toolchains.\n" | |
521 "\n" | |
522 " {{output}}\n" | |
523 " The relative path and name of the output)((s) of the current\n" | |
524 " build step. If there is more than one output, this will expand\n" | |
525 " to a list of all of them.\n" | |
526 " Example: \"out/base/my_file.o\"\n" | |
527 "\n" | |
528 " {{target_gen_dir}}\n" | |
529 " {{target_out_dir}}\n" | |
530 " The directory of the generated file and output directories,\n" | |
531 " respectively, for the current target. There is no trailing\n" | |
532 " slash.\n" | |
533 " Example: \"out/base/test\"\n" | |
534 "\n" | |
535 " {{target_output_name}}\n" | |
536 " The short name of the current target with no path information,\n" | |
537 " or the value of the \"output_name\" variable if one is specified\n" | |
538 " in the target. This will include the \"output_prefix\" if any.\n" | |
539 " Example: \"libfoo\" for the target named \"foo\" and an\n" | |
540 " output prefix for the linker tool of \"lib\".\n" | |
541 "\n" | |
542 " Compiler tools have the notion of a single input and a single output,\n" | |
543 " along with a set of compiler-specific flags. The following expansions\n" | |
544 " are available:\n" | |
545 "\n" | |
546 " {{cflags}}\n" | |
547 " {{cflags_c}}\n" | |
548 " {{cflags_cc}}\n" | |
549 " {{cflags_objc}}\n" | |
550 " {{cflags_objcc}}\n" | |
551 " {{defines}}\n" | |
jamesr
2014/08/19 19:30:41
does this have /Dxxx or -Dxxx or is it just xxx? e
| |
552 " {{include_dirs}}\n" | |
553 " Strings correspond that to the processed flags/defines/include\n" | |
554 " directories specified for the target.\n" | |
555 " Example: \"--enable-foo --enable-bar\"\n" | |
556 "\n" | |
557 " {{source}}\n" | |
558 " The relative path and name of the current input file.\n" | |
559 " Example: \"../../base/my_file.cc\"\n" | |
560 "\n" | |
561 " {{source_file_part}}\n" | |
562 " The file part of the source including the extension (with no\n" | |
563 " directory information).\n" | |
564 " Example: \"foo.cc\"\n" | |
565 "\n" | |
566 " {{source_name_part}}\n" | |
567 " The filename part of the source file with no directory or\n" | |
568 " extension.\n" | |
569 " Example: \"foo\"\n" | |
570 "\n" | |
571 " {{source_gen_dir}}\n" | |
572 " {{source_out_dir}}\n" | |
573 " The directory in the generated file and output directories,\n" | |
574 " respectively, for the current input file. If the source file\n" | |
575 " is in the same directory as the target is declared in, they will\n" | |
576 " will be the same as the \"target\" versions above.\n" | |
577 " Example: \"gen/base/test\"\n" | |
578 "\n" | |
579 " Linker tools have multiple inputs and (potentially) multiple outputs\n" | |
580 " The following expansions are available:\n" | |
581 "\n" | |
582 " {{inputs}}\n" | |
583 " Expands to the inputs to the link step. This will be a list of\n" | |
584 " object files and static libraries.\n" | |
585 " Example: \"obj/foo.o obj/bar.o obj/somelibrary.a\"\n" | |
586 "\n" | |
587 " {{ldflags}}\n" | |
588 " Expands to the processed set of ldflags and library search paths\n" | |
589 " specified for the target.\n" | |
590 " Example: \"-m64, -fPIC -pthread -L/usr/local/mylib\"\n" | |
591 "\n" | |
592 " {{libs}}\n" | |
593 " Expands to the list of system libraries to link to. Each will\n" | |
594 " be prefixed by the \"lib_prefix\".\n" | |
595 "\n" | |
596 " As a special case to support Mac, libraries with names ending in\n" | |
597 " \".framework\" will be added to the {{libs}} with \"-framework\"\n" | |
598 " preceeding it, and the lib prefix will be ignored.\n" | |
599 "\n" | |
600 " Example: \"-lfoo -lbar\"\n" | |
601 "\n" | |
602 " {{output_extension}}\n" | |
603 " The value of the \"output_extension\" variable in the target,\n" | |
604 " or the value of the \"default_output_extension\" value in the\n" | |
605 " tool if the target does not specify an output extension.\n" | |
606 " Example: \".so\"\n" | |
607 "\n" | |
608 " {{solibs}}\n" | |
609 " Extra libraries from shared library dependncies not specified\n" | |
jamesr
2014/08/19 19:30:41
typo 'dependncies' -> 'dependencies'
| |
610 " in the {{inputs}}. This is the list of link_output files from\n" | |
611 " shared libraries (if the solink tool specifies a \"link_output\"\n" | |
612 " variable separate from the \"depend_output\").\n" | |
613 "\n" | |
614 " These should basically be treated by sources by your tool.\n" | |
jamesr
2014/08/19 19:30:41
dunno what 'by sources' means - do you mean 'treat
| |
615 " Example: \"libfoo.so libbar.so\"\n" | |
616 "\n" | |
617 " The copy tool allows the common compiler/linker substitutions, plus\n" | |
618 " {{source}} which is the source of the copy. The stamp tool allows\n" | |
619 " only the common tool substitutions.\n" | |
620 "\n" | |
621 "Separate linking and dependencies for shared libraries\n" | |
622 "\n" | |
623 " Shared libraries are special in that not all changes to them require\n" | |
624 " that dependent targets be re-linked. If the shared library is changed\n" | |
625 " but no imports or exports are different, dependent code needn't be\n" | |
626 " relinked, which can speed up the build.\n" | |
627 "\n" | |
628 " If your link step can output a list of exports from a shared library\n" | |
629 " and writes the file only if the new one is different, the timestamp of\n" | |
630 " this file can be used for triggering re-links, while the actual shared\n" | |
631 " library would be used for linking.\n" | |
632 "\n" | |
633 " You will need to specify\n" | |
634 " restat = true\n" | |
635 " in the linker tool to make this work, so Ninja will detect if the\n" | |
636 " timestamp of the dependency file has changed after linking (otherwise\n" | |
637 " it will always assume that running a command updates the output):\n" | |
638 "\n" | |
639 " tool(\"solink\") {\n" | |
640 " command = \"...\"\n" | |
641 " outputs = [\n" | |
642 " \"{{root_out_dir}}/{{target_output_name}}{{output_extension}}\",\n" | |
643 " \"{{root_out_dir}}/{{target_output_name}}" | |
644 "{{output_extension}}.TOC\",\n" | |
645 " ]\n" | |
646 " link_output =\n" | |
647 " \"{{root_out_dir}}/{{target_output_name}}{{output_extension}}\",\n" | |
648 " depend_output =\n" | |
649 " \"{{root_out_dir}}/{{target_output_name}}" | |
650 "{{output_extension}}.TOC\",\n" | |
651 " restat = true\n" | |
652 " }\n" | |
232 "\n" | 653 "\n" |
233 "Example\n" | 654 "Example\n" |
234 "\n" | 655 "\n" |
235 " toolchain(\"my_toolchain\") {\n" | 656 " toolchain(\"my_toolchain\") {\n" |
236 " # Put these at the top to apply to all tools below.\n" | 657 " # Put these at the top to apply to all tools below.\n" |
237 " lib_prefix = \"-l\"\n" | 658 " lib_prefix = \"-l\"\n" |
238 " lib_dir_prefix = \"-L\"\n" | 659 " lib_dir_prefix = \"-L\"\n" |
239 "\n" | 660 "\n" |
240 " tool(\"cc\") {\n" | 661 " tool(\"cc\") {\n" |
241 " command = \"gcc \\$in -o \\$out\"\n" | 662 " command = \"gcc \\$in -o \\$out\"\n" |
663 " outputs = [ \"{{source_out_dir}}/{{source_name_part}}.o\"\n" | |
242 " description = \"GCC \\$in\"\n" | 664 " description = \"GCC \\$in\"\n" |
243 " }\n" | 665 " }\n" |
244 " tool(\"cxx\") {\n" | 666 " tool(\"cxx\") {\n" |
245 " command = \"g++ \\$in -o \\$out\"\n" | 667 " command = \"g++ \\$in -o \\$out\"\n" |
668 " outputs = [ \"{{source_out_dir}}/{{source_name_part}}.o\"\n" | |
246 " description = \"G++ \\$in\"\n" | 669 " description = \"G++ \\$in\"\n" |
247 " }\n" | 670 " }\n" |
248 " }\n"; | 671 " }\n"; |
249 | 672 |
250 Value RunTool(Scope* scope, | 673 Value RunTool(Scope* scope, |
251 const FunctionCallNode* function, | 674 const FunctionCallNode* function, |
252 const std::vector<Value>& args, | 675 const std::vector<Value>& args, |
253 BlockNode* block, | 676 BlockNode* block, |
254 Err* err) { | 677 Err* err) { |
255 // Find the toolchain definition we're executing inside of. The toolchain | 678 // Find the toolchain definition we're executing inside of. The toolchain |
(...skipping 15 matching lines...) Expand all Loading... | |
271 *err = Err(args[0], "Unknown tool type"); | 694 *err = Err(args[0], "Unknown tool type"); |
272 return Value(); | 695 return Value(); |
273 } | 696 } |
274 | 697 |
275 // Run the tool block. | 698 // Run the tool block. |
276 Scope block_scope(scope); | 699 Scope block_scope(scope); |
277 block->ExecuteBlockInScope(&block_scope, err); | 700 block->ExecuteBlockInScope(&block_scope, err); |
278 if (err->has_error()) | 701 if (err->has_error()) |
279 return Value(); | 702 return Value(); |
280 | 703 |
281 // Extract the stuff we need. | 704 // Figure out which validator to use for the substitution pattern for this |
282 Toolchain::Tool t; | 705 // tool type. There are different validators for the "outputs" than for the |
283 if (!ReadString(block_scope, "command", &t.command, err) || | 706 // rest of the strings. |
284 !ReadString(block_scope, "depfile", &t.depfile, err) || | 707 bool (*subst_validator)(SubstitutionType) = NULL; |
285 // TODO(brettw) delete this once we rename "deps" -> "depsformat" in | 708 bool (*subst_output_validator)(SubstitutionType) = NULL; |
286 // the toolchain definitions. This will avoid colliding with the | 709 if (IsCompilerTool(tool_type)) { |
287 // toolchain's "deps" list. For now, accept either. | 710 subst_validator = &IsValidCompilerSubstitution; |
288 !ReadString(block_scope, "deps", &t.depsformat, err) || | 711 subst_output_validator = &IsValidCompilerOutputsSubstitution; |
289 !ReadString(block_scope, "depsformat", &t.depsformat, err) || | 712 } else if (IsLinkerTool(tool_type)) { |
290 !ReadString(block_scope, "description", &t.description, err) || | 713 subst_validator = &IsValidLinkerSubstitution; |
291 !ReadString(block_scope, "lib_dir_prefix", &t.lib_dir_prefix, err) || | 714 subst_output_validator = &IsValidLinkerOutputsSubstitution; |
292 !ReadString(block_scope, "lib_prefix", &t.lib_prefix, err) || | 715 } else if (tool_type == Toolchain::TYPE_COPY) { |
293 !ReadString(block_scope, "pool", &t.pool, err) || | 716 subst_validator = &IsValidCopySubstitution; |
294 !ReadString(block_scope, "restat", &t.restat, err) || | 717 subst_output_validator = &IsValidCopySubstitution; |
295 !ReadString(block_scope, "rspfile", &t.rspfile, err) || | 718 } else { |
296 !ReadString(block_scope, "rspfile_content", &t.rspfile_content, err)) | 719 subst_validator = &IsValidToolSubstutition; |
720 subst_output_validator = &IsValidToolSubstutition; | |
721 } | |
722 | |
723 scoped_ptr<Tool> tool(new Tool); | |
724 | |
725 if (!ReadPattern(&block_scope, "command", subst_validator, tool.get(), | |
726 &Tool::set_command, err) || | |
727 !ReadOutputExtension(&block_scope, tool.get(), err) || | |
728 !ReadPattern(&block_scope, "depfile", subst_validator, tool.get(), | |
729 &Tool::set_depfile, err) || | |
730 !ReadDepsFormat(&block_scope, tool.get(), err) || | |
731 !ReadPattern(&block_scope, "description", subst_validator, tool.get(), | |
732 &Tool::set_description, err) || | |
733 !ReadString(&block_scope, "lib_switch", tool.get(), | |
734 &Tool::set_lib_switch, err) || | |
735 !ReadString(&block_scope, "lib_dir_switch", tool.get(), | |
736 &Tool::set_lib_dir_switch, err) || | |
737 !ReadPattern(&block_scope, "link_output", subst_validator, tool.get(), | |
738 &Tool::set_link_output, err) || | |
739 !ReadPattern(&block_scope, "depend_output", subst_validator, tool.get(), | |
740 &Tool::set_depend_output, err) || | |
741 !ReadString(&block_scope, "output_prefix", tool.get(), | |
742 &Tool::set_output_prefix, err) || | |
743 !ReadString(&block_scope, "pool", tool.get(), &Tool::set_pool, err) || | |
744 !ReadBool(&block_scope, "restat", tool.get(), &Tool::set_restat, err) || | |
745 !ReadPattern(&block_scope, "rspfile", subst_validator, tool.get(), | |
746 &Tool::set_rspfile, err) || | |
747 !ReadPattern(&block_scope, "rspfile_content", subst_validator, tool.get(), | |
748 &Tool::set_rspfile_content, err)) { | |
297 return Value(); | 749 return Value(); |
750 } | |
751 | |
752 if (tool_type != Toolchain::TYPE_COPY && tool_type != Toolchain::TYPE_STAMP) { | |
753 // All tools except the copy and stamp tools should have outputs. The copy | |
754 // and stamp tool's outputs are generated internally. | |
755 if (!ReadOutputs(&block_scope, function, subst_output_validator, | |
756 tool.get(), err)) | |
757 return Value(); | |
758 } | |
759 | |
760 // Validate that the link_output and depend_output refer to items in the | |
761 // outputs and aren't defined for irrelevant tool types. | |
762 if (!tool->link_output().empty()) { | |
763 if (tool_type != Toolchain::TYPE_SOLINK) { | |
764 *err = Err(function, "This tool specifies a link_output.", | |
765 "This is only valid for solink tools."); | |
766 return Value(); | |
767 } | |
768 if (!IsPatternInOutputList(tool->outputs(), tool->link_output())) { | |
769 *err = Err(function, "This tool's link_output is bad.", | |
770 "It must match one of the outputs."); | |
771 return Value(); | |
772 } | |
773 } | |
774 if (!tool->depend_output().empty()) { | |
775 if (tool_type != Toolchain::TYPE_SOLINK) { | |
776 *err = Err(function, "This tool specifies a depend_output.", | |
777 "This is only valid for solink tools."); | |
778 return Value(); | |
779 } | |
780 if (!IsPatternInOutputList(tool->outputs(), tool->depend_output())) { | |
781 *err = Err(function, "This tool's depend_output is bad.", | |
782 "It must match one of the outputs."); | |
783 return Value(); | |
784 } | |
785 } | |
786 if ((!tool->link_output().empty() && tool->depend_output().empty()) || | |
787 (tool->link_output().empty() && !tool->depend_output().empty())) { | |
788 *err = Err(function, "Both link_output and depend_output should either " | |
789 "be specified or they should both be empty."); | |
790 return Value(); | |
791 } | |
298 | 792 |
299 // Make sure there weren't any vars set in this tool that were unused. | 793 // Make sure there weren't any vars set in this tool that were unused. |
300 if (!block_scope.CheckForUnusedVars(err)) | 794 if (!block_scope.CheckForUnusedVars(err)) |
301 return Value(); | 795 return Value(); |
302 | 796 |
303 toolchain->SetTool(tool_type, t); | 797 toolchain->SetTool(tool_type, tool.Pass()); |
304 return Value(); | 798 return Value(); |
305 } | 799 } |
306 | 800 |
307 // toolchain_args -------------------------------------------------------------- | 801 // toolchain_args -------------------------------------------------------------- |
308 | 802 |
309 extern const char kToolchainArgs[] = "toolchain_args"; | 803 extern const char kToolchainArgs[] = "toolchain_args"; |
310 extern const char kToolchainArgs_HelpShort[] = | 804 extern const char kToolchainArgs_HelpShort[] = |
311 "toolchain_args: Set build arguments for toolchain build setup."; | 805 "toolchain_args: Set build arguments for toolchain build setup."; |
312 extern const char kToolchainArgs_Help[] = | 806 extern const char kToolchainArgs_Help[] = |
313 "toolchain_args: Set build arguments for toolchain build setup.\n" | 807 "toolchain_args: Set build arguments for toolchain build setup.\n" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
374 return Value(); | 868 return Value(); |
375 | 869 |
376 Scope::KeyValueMap values; | 870 Scope::KeyValueMap values; |
377 block_scope.GetCurrentScopeValues(&values); | 871 block_scope.GetCurrentScopeValues(&values); |
378 toolchain->args() = values; | 872 toolchain->args() = values; |
379 | 873 |
380 return Value(); | 874 return Value(); |
381 } | 875 } |
382 | 876 |
383 } // namespace functions | 877 } // namespace functions |
OLD | NEW |