| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "tools/gn/functions.h" | |
| 6 | |
| 7 #include <iostream> | |
| 8 | |
| 9 #include "base/strings/string_util.h" | |
| 10 #include "tools/gn/config.h" | |
| 11 #include "tools/gn/config_values_generator.h" | |
| 12 #include "tools/gn/err.h" | |
| 13 #include "tools/gn/input_file.h" | |
| 14 #include "tools/gn/item_tree.h" | |
| 15 #include "tools/gn/parse_tree.h" | |
| 16 #include "tools/gn/scheduler.h" | |
| 17 #include "tools/gn/scope.h" | |
| 18 #include "tools/gn/settings.h" | |
| 19 #include "tools/gn/target_manager.h" | |
| 20 #include "tools/gn/token.h" | |
| 21 #include "tools/gn/value.h" | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 void FillNeedsBlockError(const FunctionCallNode* function, Err* err) { | |
| 26 *err = Err(function->function(), "This function call requires a block.", | |
| 27 "The block's \"{\" must be on the same line as the function " | |
| 28 "call's \")\"."); | |
| 29 } | |
| 30 | |
| 31 Value ExecuteAssert(const FunctionCallNode* function, | |
| 32 const std::vector<Value>& args, | |
| 33 Err* err) { | |
| 34 if (args.size() != 1) { | |
| 35 *err = Err(function->function(), "Wrong number of arguments.", | |
| 36 "assert() takes one argument, " | |
| 37 "were you expecting somethig else?"); | |
| 38 } else if (args[0].InterpretAsInt() == 0) { | |
| 39 *err = Err(function->function(), "Assertion failed."); | |
| 40 if (args[0].origin()) { | |
| 41 // If you do "assert(foo)" we'd ideally like to show you where foo was | |
| 42 // set, and in this case the origin of the args will tell us that. | |
| 43 // However, if you do "assert(foo && bar)" the source of the value will | |
| 44 // be the assert like, which isn't so helpful. | |
| 45 // | |
| 46 // So we try to see if the args are from the same line or not. This will | |
| 47 // break if you do "assert(\nfoo && bar)" and we may show the second line | |
| 48 // as the source, oh well. The way around this is to check to see if the | |
| 49 // origin node is inside our function call block. | |
| 50 Location origin_location = args[0].origin()->GetRange().begin(); | |
| 51 if (origin_location.file() != function->function().location().file() || | |
| 52 origin_location.line_number() != | |
| 53 function->function().location().line_number()) { | |
| 54 err->AppendSubErr(Err(args[0].origin()->GetRange(), "", | |
| 55 "This is where it was set.")); | |
| 56 } | |
| 57 } | |
| 58 } | |
| 59 return Value(); | |
| 60 } | |
| 61 | |
| 62 Value ExecuteConfig(Scope* scope, | |
| 63 const FunctionCallNode* function, | |
| 64 const std::vector<Value>& args, | |
| 65 Err* err) { | |
| 66 if (!EnsureSingleStringArg(function, args, err) || | |
| 67 !EnsureNotProcessingImport(function, scope, err)) | |
| 68 return Value(); | |
| 69 | |
| 70 Label label(MakeLabelForScope(scope, function, args[0].string_value())); | |
| 71 | |
| 72 if (g_scheduler->verbose_logging()) | |
| 73 g_scheduler->Log("Generating config", label.GetUserVisibleName(true)); | |
| 74 | |
| 75 // Create the empty config object. | |
| 76 ItemTree* tree = &scope->settings()->build_settings()->item_tree(); | |
| 77 Config* config = Config::GetConfig(scope->settings(), function->GetRange(), | |
| 78 label, NULL, err); | |
| 79 if (err->has_error()) | |
| 80 return Value(); | |
| 81 | |
| 82 // Fill it. | |
| 83 const SourceDir input_dir = SourceDirForFunctionCall(function); | |
| 84 ConfigValuesGenerator gen(&config->config_values(), scope, | |
| 85 function->function(), input_dir, err); | |
| 86 gen.Run(); | |
| 87 if (err->has_error()) | |
| 88 return Value(); | |
| 89 | |
| 90 // Mark as complete. | |
| 91 { | |
| 92 base::AutoLock lock(tree->lock()); | |
| 93 tree->MarkItemGeneratedLocked(label); | |
| 94 } | |
| 95 return Value(); | |
| 96 } | |
| 97 | |
| 98 Value ExecuteDeclareArgs(Scope* scope, | |
| 99 const FunctionCallNode* function, | |
| 100 const std::vector<Value>& args, | |
| 101 Err* err) { | |
| 102 // Only allow this to be called once. We use a variable in the current scope | |
| 103 // with a name the parser will reject if the user tried to type it. | |
| 104 const char did_declare_args_var[] = "@@declared_args"; | |
| 105 if (scope->GetValue(did_declare_args_var)) { | |
| 106 *err = Err(function->function(), "Duplicate call to declared_args."); | |
| 107 err->AppendSubErr( | |
| 108 Err(scope->GetValue(did_declare_args_var)->origin()->GetRange(), | |
| 109 "See the original call.")); | |
| 110 return Value(); | |
| 111 } | |
| 112 | |
| 113 // Find the root scope where the values will be set. | |
| 114 Scope* root = scope->mutable_containing(); | |
| 115 if (!root || root->containing() || !scope->IsProcessingBuildConfig()) { | |
| 116 *err = Err(function->function(), "declare_args called incorrectly." | |
| 117 "It must be called only from the build config script and in the " | |
| 118 "root scope."); | |
| 119 return Value(); | |
| 120 } | |
| 121 | |
| 122 // Take all variables set in the current scope as default values and put | |
| 123 // them in the parent scope. The values in the current scope are the defaults, | |
| 124 // then we apply the external args to this list. | |
| 125 Scope::KeyValueVector values; | |
| 126 scope->GetCurrentScopeValues(&values); | |
| 127 for (size_t i = 0; i < values.size(); i++) { | |
| 128 // TODO(brettw) actually import the arguments from the command line rather | |
| 129 // than only using the defaults. | |
| 130 root->SetValue(values[i].first, values[i].second, | |
| 131 values[i].second.origin()); | |
| 132 } | |
| 133 | |
| 134 scope->SetValue(did_declare_args_var, Value(function, 1), NULL); | |
| 135 return Value(); | |
| 136 } | |
| 137 | |
| 138 Value ExecuteImport(Scope* scope, | |
| 139 const FunctionCallNode* function, | |
| 140 const std::vector<Value>& args, | |
| 141 Err* err) { | |
| 142 if (!EnsureSingleStringArg(function, args, err) || | |
| 143 !EnsureNotProcessingImport(function, scope, err)) | |
| 144 return Value(); | |
| 145 | |
| 146 const SourceDir input_dir = SourceDirForFunctionCall(function); | |
| 147 SourceFile import_file = | |
| 148 input_dir.ResolveRelativeFile(args[0].string_value()); | |
| 149 scope->settings()->import_manager().DoImport(import_file, function, | |
| 150 scope, err); | |
| 151 return Value(); | |
| 152 } | |
| 153 | |
| 154 Value ExecuteTemplate(Scope* scope, | |
| 155 const FunctionCallNode* invocation, | |
| 156 const std::vector<Value>& args, | |
| 157 BlockNode* block, | |
| 158 const FunctionCallNode* rule, | |
| 159 Err* err) { | |
| 160 if (!EnsureNotProcessingImport(invocation, scope, err)) | |
| 161 return Value(); | |
| 162 Scope block_scope(scope); | |
| 163 if (!FillTargetBlockScope(scope, invocation, | |
| 164 invocation->function().value().data(), | |
| 165 block, args, &block_scope, err)) | |
| 166 return Value(); | |
| 167 | |
| 168 // Run the block for the rule invocation. | |
| 169 block->ExecuteBlockInScope(&block_scope, err); | |
| 170 if (err->has_error()) | |
| 171 return Value(); | |
| 172 | |
| 173 // Now run the rule itself with that block as the current scope. | |
| 174 rule->block()->ExecuteBlockInScope(&block_scope, err); | |
| 175 if (err->has_error()) | |
| 176 return Value(); | |
| 177 | |
| 178 return Value(); | |
| 179 } | |
| 180 | |
| 181 Value ExecuteSetDefaults(Scope* scope, | |
| 182 const FunctionCallNode* function, | |
| 183 const std::vector<Value>& args, | |
| 184 BlockNode* block, | |
| 185 Err* err) { | |
| 186 if (!EnsureSingleStringArg(function, args, err)) | |
| 187 return Value(); | |
| 188 const std::string& target_type(args[0].string_value()); | |
| 189 | |
| 190 // Ensure there aren't defaults already set. | |
| 191 if (scope->GetTargetDefaults(target_type)) { | |
| 192 *err = Err(function->function(), | |
| 193 "This target type defaults were already set."); | |
| 194 return Value(); | |
| 195 } | |
| 196 | |
| 197 // Execute the block in a new scope that has a parent of the containing | |
| 198 // scope. | |
| 199 Scope block_scope(scope); | |
| 200 if (!FillTargetBlockScope(scope, function, | |
| 201 function->function().value().data(), | |
| 202 block, args, &block_scope, err)) | |
| 203 return Value(); | |
| 204 | |
| 205 // Run the block for the rule invocation. | |
| 206 block->ExecuteBlockInScope(&block_scope, err); | |
| 207 if (err->has_error()) | |
| 208 return Value(); | |
| 209 | |
| 210 // Now copy the values set on the scope we made into the free-floating one | |
| 211 // (with no containing scope) used to hold the target defaults. | |
| 212 Scope* dest = scope->MakeTargetDefaults(target_type); | |
| 213 block_scope.NonRecursiveMergeTo(dest, function, "<SHOULD NOT FAIL>", err); | |
| 214 return Value(); | |
| 215 } | |
| 216 | |
| 217 Value ExecuteSetSourcesAssignmentFilter(Scope* scope, | |
| 218 const FunctionCallNode* function, | |
| 219 const std::vector<Value>& args, | |
| 220 Err* err) { | |
| 221 if (args.size() != 1) { | |
| 222 *err = Err(function, "set_sources_assignment_filter takes one argument."); | |
| 223 } else { | |
| 224 scoped_ptr<PatternList> f(new PatternList); | |
| 225 f->SetFromValue(args[0], err); | |
| 226 if (!err->has_error()) | |
| 227 scope->set_sources_assignment_filter(f.Pass()); | |
| 228 } | |
| 229 return Value(); | |
| 230 } | |
| 231 | |
| 232 // void print(...) | |
| 233 // prints all arguments to the console separated by spaces. | |
| 234 Value ExecutePrint(const std::vector<Value>& args, Err* err) { | |
| 235 for (size_t i = 0; i < args.size(); i++) { | |
| 236 if (i != 0) | |
| 237 std::cout << " "; | |
| 238 std::cout << args[i].ToString(); | |
| 239 } | |
| 240 std::cout << std::endl; | |
| 241 return Value(); | |
| 242 } | |
| 243 | |
| 244 } // namespace | |
| 245 | |
| 246 // ---------------------------------------------------------------------------- | |
| 247 | |
| 248 namespace functions { | |
| 249 | |
| 250 const char kAssert[] = "assert"; | |
| 251 const char kComponent[] = "component"; | |
| 252 const char kConfig[] = "config"; | |
| 253 const char kCopy[] = "copy"; | |
| 254 const char kCustom[] = "custom"; | |
| 255 const char kDeclareArgs[] = "declare_args"; | |
| 256 const char kExecScript[] = "exec_script"; | |
| 257 const char kExecutable[] = "executable"; | |
| 258 const char kGroup[] = "group"; | |
| 259 const char kImport[] = "import"; | |
| 260 const char kPrint[] = "print"; | |
| 261 const char kProcessFileTemplate[] = "process_file_template"; | |
| 262 const char kReadFile[] = "read_file"; | |
| 263 const char kSetDefaults[] = "set_defaults"; | |
| 264 const char kSetDefaultToolchain[] = "set_default_toolchain"; | |
| 265 const char kSetSourcesAssignmentFilter[] = "set_sources_assignment_filter"; | |
| 266 const char kSharedLibrary[] = "shared_library"; | |
| 267 const char kStaticLibrary[] = "static_library"; | |
| 268 const char kTemplate[] = "template"; | |
| 269 const char kTool[] = "tool"; | |
| 270 const char kToolchain[] = "toolchain"; | |
| 271 const char kTest[] = "test"; | |
| 272 const char kWriteFile[] = "write_file"; | |
| 273 | |
| 274 } // namespace functions | |
| 275 | |
| 276 // ---------------------------------------------------------------------------- | |
| 277 | |
| 278 bool EnsureNotProcessingImport(const ParseNode* node, | |
| 279 const Scope* scope, | |
| 280 Err* err) { | |
| 281 if (scope->IsProcessingImport()) { | |
| 282 *err = Err(node, "Not valid from an import.", | |
| 283 "We need to talk about this thing you are doing here. Doing this\n" | |
| 284 "kind of thing from an imported file makes me feel like you are\n" | |
| 285 "abusing me. Imports are for defining defaults, variables, and rules.\n" | |
| 286 "The appropriate place for this kind of thing is really in a normal\n" | |
| 287 "BUILD file."); | |
| 288 return false; | |
| 289 } | |
| 290 return true; | |
| 291 } | |
| 292 | |
| 293 bool EnsureNotProcessingBuildConfig(const ParseNode* node, | |
| 294 const Scope* scope, | |
| 295 Err* err) { | |
| 296 if (scope->IsProcessingBuildConfig()) { | |
| 297 *err = Err(node, "Not valid from the build config.", | |
| 298 "You can't do this kind of thing from the build config script, " | |
| 299 "silly!\nPut it in a regular BUILD file."); | |
| 300 return false; | |
| 301 } | |
| 302 return true; | |
| 303 } | |
| 304 | |
| 305 bool FillTargetBlockScope(const Scope* scope, | |
| 306 const FunctionCallNode* function, | |
| 307 const char* target_type, | |
| 308 const BlockNode* block, | |
| 309 const std::vector<Value>& args, | |
| 310 Scope* block_scope, | |
| 311 Err* err) { | |
| 312 if (!block) { | |
| 313 FillNeedsBlockError(function, err); | |
| 314 return false; | |
| 315 } | |
| 316 | |
| 317 // Copy the target defaults, if any, into the scope we're going to execute | |
| 318 // the block in. | |
| 319 const Scope* default_scope = scope->GetTargetDefaults(target_type); | |
| 320 if (default_scope) { | |
| 321 if (!default_scope->NonRecursiveMergeTo(block_scope, function, | |
| 322 "target defaults", err)) | |
| 323 return false; | |
| 324 } | |
| 325 | |
| 326 // The name is the single argument to the target function. | |
| 327 if (!EnsureSingleStringArg(function, args, err)) | |
| 328 return false; | |
| 329 | |
| 330 // Set the target name variable to the current target, and mark it used | |
| 331 // because we don't want to issue an error if the script ignores it. | |
| 332 const base::StringPiece target_name("target_name"); | |
| 333 block_scope->SetValue(target_name, Value(function, args[0].string_value()), | |
| 334 function); | |
| 335 block_scope->MarkUsed(target_name); | |
| 336 return true; | |
| 337 } | |
| 338 | |
| 339 bool EnsureSingleStringArg(const FunctionCallNode* function, | |
| 340 const std::vector<Value>& args, | |
| 341 Err* err) { | |
| 342 if (args.size() != 1) { | |
| 343 *err = Err(function->function(), "Incorrect arguments.", | |
| 344 "This function requires a single string argument."); | |
| 345 return false; | |
| 346 } | |
| 347 return args[0].VerifyTypeIs(Value::STRING, err); | |
| 348 } | |
| 349 | |
| 350 const SourceDir& SourceDirForFunctionCall(const FunctionCallNode* function) { | |
| 351 return function->function().location().file()->dir(); | |
| 352 } | |
| 353 | |
| 354 const Label& ToolchainLabelForScope(const Scope* scope) { | |
| 355 return scope->settings()->toolchain()->label(); | |
| 356 } | |
| 357 | |
| 358 Label MakeLabelForScope(const Scope* scope, | |
| 359 const FunctionCallNode* function, | |
| 360 const std::string& name) { | |
| 361 const SourceDir& input_dir = SourceDirForFunctionCall(function); | |
| 362 const Label& toolchain_label = ToolchainLabelForScope(scope); | |
| 363 return Label(input_dir, name, toolchain_label.dir(), toolchain_label.name()); | |
| 364 } | |
| 365 | |
| 366 Value ExecuteFunction(Scope* scope, | |
| 367 const FunctionCallNode* function, | |
| 368 const std::vector<Value>& args, | |
| 369 BlockNode* block, | |
| 370 Err* err) { | |
| 371 const Token& name = function->function(); | |
| 372 if (block) { | |
| 373 // These target generators need to execute the block themselves. | |
| 374 if (name.IsIdentifierEqualTo(functions::kComponent)) | |
| 375 return ExecuteComponent(scope, function, args, block, err); | |
| 376 if (name.IsIdentifierEqualTo(functions::kCustom)) | |
| 377 return ExecuteCustom(scope, function, args, block, err); | |
| 378 if (name.IsIdentifierEqualTo(functions::kExecutable)) | |
| 379 return ExecuteExecutable(scope, function, args, block, err); | |
| 380 if (name.IsIdentifierEqualTo(functions::kSetDefaults)) | |
| 381 return ExecuteSetDefaults(scope, function, args, block, err); | |
| 382 if (name.IsIdentifierEqualTo(functions::kSharedLibrary)) | |
| 383 return ExecuteSharedLibrary(scope, function, args, block, err); | |
| 384 if (name.IsIdentifierEqualTo(functions::kStaticLibrary)) | |
| 385 return ExecuteStaticLibrary(scope, function, args, block, err); | |
| 386 if (name.IsIdentifierEqualTo(functions::kGroup)) | |
| 387 return ExecuteGroup(scope, function, args, block, err); | |
| 388 if (name.IsIdentifierEqualTo(functions::kTest)) | |
| 389 return ExecuteExecutable(scope, function, args, block, err); | |
| 390 if (name.IsIdentifierEqualTo(functions::kTemplate)) | |
| 391 return ExecuteTemplate(scope, function, args, block, err); | |
| 392 if (name.IsIdentifierEqualTo(functions::kTool)) | |
| 393 return ExecuteTool(scope, function, args, block, err); | |
| 394 if (name.IsIdentifierEqualTo(functions::kToolchain)) | |
| 395 return ExecuteToolchain(scope, function, args, block, err); | |
| 396 | |
| 397 const FunctionCallNode* rule = | |
| 398 scope->GetTemplate(function->function().value().as_string()); | |
| 399 if (rule) | |
| 400 return ExecuteTemplate(scope, function, args, block, rule, err); | |
| 401 | |
| 402 // FIXME(brettw) This is not right, what if you specify a function that | |
| 403 // doesn't take a block but specify one?!?!? | |
| 404 | |
| 405 // The rest of the functions can take a pre-executed block for simplicity. | |
| 406 Scope block_scope(scope); | |
| 407 block->ExecuteBlockInScope(&block_scope, err); | |
| 408 if (err->has_error()) | |
| 409 return Value(); | |
| 410 | |
| 411 if (name.IsIdentifierEqualTo(functions::kConfig)) | |
| 412 return ExecuteConfig(&block_scope, function, args, err); | |
| 413 if (name.IsIdentifierEqualTo(functions::kCopy)) | |
| 414 return ExecuteCopy(&block_scope, function, args, err); | |
| 415 if (name.IsIdentifierEqualTo(functions::kDeclareArgs)) | |
| 416 return ExecuteDeclareArgs(&block_scope, function, args, err); | |
| 417 | |
| 418 *err = Err(name, "Unknown function."); | |
| 419 return Value(); | |
| 420 } | |
| 421 | |
| 422 if (name.IsIdentifierEqualTo(functions::kAssert)) | |
| 423 return ExecuteAssert(function, args, err); | |
| 424 if (name.IsIdentifierEqualTo(functions::kExecScript)) | |
| 425 return ExecuteExecScript(scope, function, args, err); | |
| 426 if (name.IsIdentifierEqualTo(functions::kImport)) | |
| 427 return ExecuteImport(scope, function, args, err); | |
| 428 if (name.IsIdentifierEqualTo(functions::kPrint)) | |
| 429 return ExecutePrint(args, err); | |
| 430 if (name.IsIdentifierEqualTo(functions::kProcessFileTemplate)) | |
| 431 return ExecuteProcessFileTemplate(scope, function, args, err); | |
| 432 if (name.IsIdentifierEqualTo(functions::kReadFile)) | |
| 433 return ExecuteReadFile(scope, function, args, err); | |
| 434 if (name.IsIdentifierEqualTo(functions::kSetDefaultToolchain)) | |
| 435 return ExecuteSetDefaultToolchain(scope, function, args, err); | |
| 436 if (name.IsIdentifierEqualTo(functions::kSetSourcesAssignmentFilter)) | |
| 437 return ExecuteSetSourcesAssignmentFilter(scope, function, args, err); | |
| 438 if (name.IsIdentifierEqualTo(functions::kWriteFile)) | |
| 439 return ExecuteWriteFile(scope, function, args, err); | |
| 440 | |
| 441 *err = Err(function, "Unknown function."); | |
| 442 return Value(); | |
| 443 } | |
| OLD | NEW |