Chromium Code Reviews| 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 |