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