Home | History | Annotate | Download | only in gn
      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 // This is called when a template is invoked. When we see a template
     32 // declaration, that funciton is RunTemplate.
     33 Value RunTemplateInvocation(Scope* scope,
     34                             const FunctionCallNode* invocation,
     35                             const std::vector<Value>& args,
     36                             BlockNode* block,
     37                             const FunctionCallNode* rule,
     38                             Err* err) {
     39   if (!EnsureNotProcessingImport(invocation, scope, err))
     40     return Value();
     41   Scope block_scope(scope);
     42   if (!FillTargetBlockScope(scope, invocation,
     43                             invocation->function().value().data(),
     44                             block, args, &block_scope, err))
     45     return Value();
     46 
     47   // Run the block for the rule invocation.
     48   block->ExecuteBlockInScope(&block_scope, err);
     49   if (err->has_error())
     50     return Value();
     51 
     52   // Now run the rule itself with that block as the current scope.
     53   rule->block()->ExecuteBlockInScope(&block_scope, err);
     54   if (err->has_error())
     55     return Value();
     56 
     57   return Value();
     58 }
     59 
     60 }  // namespace
     61 
     62 // ----------------------------------------------------------------------------
     63 
     64 bool EnsureNotProcessingImport(const ParseNode* node,
     65                                const Scope* scope,
     66                                Err* err) {
     67   if (scope->IsProcessingImport()) {
     68     *err = Err(node, "Not valid from an import.",
     69         "We need to talk about this thing you are doing here. Doing this\n"
     70         "kind of thing from an imported file makes me feel like you are\n"
     71         "abusing me. Imports are for defining defaults, variables, and rules.\n"
     72         "The appropriate place for this kind of thing is really in a normal\n"
     73         "BUILD file.");
     74     return false;
     75   }
     76   return true;
     77 }
     78 
     79 bool EnsureNotProcessingBuildConfig(const ParseNode* node,
     80                                     const Scope* scope,
     81                                     Err* err) {
     82   if (scope->IsProcessingBuildConfig()) {
     83     *err = Err(node, "Not valid from the build config.",
     84         "You can't do this kind of thing from the build config script, "
     85         "silly!\nPut it in a regular BUILD file.");
     86     return false;
     87   }
     88   return true;
     89 }
     90 
     91 bool FillTargetBlockScope(const Scope* scope,
     92                           const FunctionCallNode* function,
     93                           const char* target_type,
     94                           const BlockNode* block,
     95                           const std::vector<Value>& args,
     96                           Scope* block_scope,
     97                           Err* err) {
     98   if (!block) {
     99     FillNeedsBlockError(function, err);
    100     return false;
    101   }
    102 
    103   // Copy the target defaults, if any, into the scope we're going to execute
    104   // the block in.
    105   const Scope* default_scope = scope->GetTargetDefaults(target_type);
    106   if (default_scope) {
    107     if (!default_scope->NonRecursiveMergeTo(block_scope, function,
    108                                             "target defaults", err))
    109       return false;
    110   }
    111 
    112   // The name is the single argument to the target function.
    113   if (!EnsureSingleStringArg(function, args, err))
    114     return false;
    115 
    116   // Set the target name variable to the current target, and mark it used
    117   // because we don't want to issue an error if the script ignores it.
    118   const base::StringPiece target_name("target_name");
    119   block_scope->SetValue(target_name, Value(function, args[0].string_value()),
    120                         function);
    121   block_scope->MarkUsed(target_name);
    122   return true;
    123 }
    124 
    125 bool EnsureSingleStringArg(const FunctionCallNode* function,
    126                            const std::vector<Value>& args,
    127                            Err* err) {
    128   if (args.size() != 1) {
    129     *err = Err(function->function(), "Incorrect arguments.",
    130                "This function requires a single string argument.");
    131     return false;
    132   }
    133   return args[0].VerifyTypeIs(Value::STRING, err);
    134 }
    135 
    136 const SourceDir& SourceDirForFunctionCall(const FunctionCallNode* function) {
    137   return function->function().location().file()->dir();
    138 }
    139 
    140 const Label& ToolchainLabelForScope(const Scope* scope) {
    141   return scope->settings()->toolchain()->label();
    142 }
    143 
    144 Label MakeLabelForScope(const Scope* scope,
    145                         const FunctionCallNode* function,
    146                         const std::string& name) {
    147   const SourceDir& input_dir = SourceDirForFunctionCall(function);
    148   const Label& toolchain_label = ToolchainLabelForScope(scope);
    149   return Label(input_dir, name, toolchain_label.dir(), toolchain_label.name());
    150 }
    151 
    152 namespace functions {
    153 
    154 // assert ----------------------------------------------------------------------
    155 
    156 const char kAssert[] = "assert";
    157 const char kAssert_Help[] =
    158     "TODO(brettw) WRITE ME";
    159 
    160 Value RunAssert(Scope* scope,
    161                 const FunctionCallNode* function,
    162                 const std::vector<Value>& args,
    163                 Err* err) {
    164   if (args.size() != 1) {
    165     *err = Err(function->function(), "Wrong number of arguments.",
    166                "assert() takes one argument, "
    167                "were you expecting somethig else?");
    168   } else if (args[0].InterpretAsInt() == 0) {
    169     *err = Err(function->function(), "Assertion failed.");
    170     if (args[0].origin()) {
    171       // If you do "assert(foo)" we'd ideally like to show you where foo was
    172       // set, and in this case the origin of the args will tell us that.
    173       // However, if you do "assert(foo && bar)" the source of the value will
    174       // be the assert like, which isn't so helpful.
    175       //
    176       // So we try to see if the args are from the same line or not. This will
    177       // break if you do "assert(\nfoo && bar)" and we may show the second line
    178       // as the source, oh well. The way around this is to check to see if the
    179       // origin node is inside our function call block.
    180       Location origin_location = args[0].origin()->GetRange().begin();
    181       if (origin_location.file() != function->function().location().file() ||
    182           origin_location.line_number() !=
    183               function->function().location().line_number()) {
    184         err->AppendSubErr(Err(args[0].origin()->GetRange(), "",
    185                               "This is where it was set."));
    186       }
    187     }
    188   }
    189   return Value();
    190 }
    191 
    192 // config ----------------------------------------------------------------------
    193 
    194 const char kConfig[] = "config";
    195 const char kConfig_Help[] =
    196     "TODO(brettw) write this.";
    197 
    198 Value RunConfig(const FunctionCallNode* function,
    199                 const std::vector<Value>& args,
    200                 Scope* scope,
    201                 Err* err) {
    202   if (!EnsureSingleStringArg(function, args, err) ||
    203       !EnsureNotProcessingImport(function, scope, err))
    204     return Value();
    205 
    206   Label label(MakeLabelForScope(scope, function, args[0].string_value()));
    207 
    208   if (g_scheduler->verbose_logging())
    209     g_scheduler->Log("Generating config", label.GetUserVisibleName(true));
    210 
    211   // Create the empty config object.
    212   ItemTree* tree = &scope->settings()->build_settings()->item_tree();
    213   Config* config = Config::GetConfig(scope->settings(), function->GetRange(),
    214                                      label, NULL, err);
    215   if (err->has_error())
    216     return Value();
    217 
    218   // Fill it.
    219   const SourceDir input_dir = SourceDirForFunctionCall(function);
    220   ConfigValuesGenerator gen(&config->config_values(), scope,
    221                             function->function(), input_dir, err);
    222   gen.Run();
    223   if (err->has_error())
    224     return Value();
    225 
    226   // Mark as complete.
    227   {
    228     base::AutoLock lock(tree->lock());
    229     tree->MarkItemDefinedLocked(scope->settings()->build_settings(), label,
    230                                 err);
    231   }
    232   return Value();
    233 }
    234 
    235 // declare_args ----------------------------------------------------------------
    236 
    237 const char kDeclareArgs[] = "declare_args";
    238 const char kDeclareArgs_Help[] =
    239     "TODO(brettw) write this.";
    240 
    241 Value RunDeclareArgs(const FunctionCallNode* function,
    242                      const std::vector<Value>& args,
    243                      Scope* scope,
    244                      Err* err) {
    245   // Only allow this to be called once. We use a variable in the current scope
    246   // with a name the parser will reject if the user tried to type it.
    247   const char did_declare_args_var[] = "@@declared_args";
    248   if (scope->GetValue(did_declare_args_var)) {
    249     *err = Err(function->function(), "Duplicate call to declared_args.");
    250     err->AppendSubErr(
    251         Err(scope->GetValue(did_declare_args_var)->origin()->GetRange(),
    252                             "See the original call."));
    253     return Value();
    254   }
    255 
    256   // Find the root scope where the values will be set.
    257   Scope* root = scope->mutable_containing();
    258   if (!root || root->containing() || !scope->IsProcessingBuildConfig()) {
    259     *err = Err(function->function(), "declare_args called incorrectly."
    260         "It must be called only from the build config script and in the "
    261         "root scope.");
    262     return Value();
    263   }
    264 
    265   // Take all variables set in the current scope as default values and put
    266   // them in the parent scope. The values in the current scope are the defaults,
    267   // then we apply the external args to this list.
    268   Scope::KeyValueVector values;
    269   scope->GetCurrentScopeValues(&values);
    270   for (size_t i = 0; i < values.size(); i++) {
    271     // TODO(brettw) actually import the arguments from the command line rather
    272     // than only using the defaults.
    273     root->SetValue(values[i].first, values[i].second,
    274                    values[i].second.origin());
    275   }
    276 
    277   scope->SetValue(did_declare_args_var, Value(function, 1), NULL);
    278   return Value();
    279 }
    280 
    281 // import ----------------------------------------------------------------------
    282 
    283 const char kImport[] = "import";
    284 const char kImport_Help[] =
    285     "import: Import a file into the current scope.\n"
    286     "\n"
    287     "  The import command loads the rules and variables resulting from\n"
    288     "  executing the given file into the current scope.\n"
    289     "\n"
    290     "  By convention, imported files are named with a .gni extension.\n"
    291     "\n"
    292     "  It does not do an \"include\". The imported file is executed in a\n"
    293     "  standalone environment from the caller of the import command. The\n"
    294     "  results of this execution are cached for other files that import the\n"
    295     "  same .gni file.\n"
    296     "\n"
    297     "  Note that you can not import a BUILD.gn file that's otherwise used\n"
    298     "  in the build. Files must either be imported or implicitly loaded as\n"
    299     "  a result of deps rules, but not both.\n"
    300     "\n"
    301     "  The imported file's scope will be merged with the scope at the point\n"
    302     "  import was called. If there is a conflict (both the current scope and\n"
    303     "  the imported file define some variable or rule with the same name)\n"
    304     "  a runtime error will be thrown. Therefore, it's good practice to\n"
    305     "  minimize the stuff that an imported file defines.\n"
    306     "\n"
    307     "Examples:\n"
    308     "\n"
    309     "  import(\"//build/rules/idl_compilation_rule.gni\")\n"
    310     "\n"
    311     "  # Looks in the current directory.\n"
    312     "  import(\"my_vars.gni\")\n";
    313 
    314 Value RunImport(Scope* scope,
    315                 const FunctionCallNode* function,
    316                 const std::vector<Value>& args,
    317                 Err* err) {
    318   if (!EnsureSingleStringArg(function, args, err) ||
    319       !EnsureNotProcessingImport(function, scope, err))
    320     return Value();
    321 
    322   const SourceDir input_dir = SourceDirForFunctionCall(function);
    323   SourceFile import_file =
    324       input_dir.ResolveRelativeFile(args[0].string_value());
    325   scope->settings()->import_manager().DoImport(import_file, function,
    326                                                scope, err);
    327   return Value();
    328 }
    329 
    330 // set_defaults ----------------------------------------------------------------
    331 
    332 const char kSetDefaults[] = "set_defaults";
    333 const char kSetDefaults_Help[] =
    334     "TODO(brettw) write this.";
    335 
    336 Value RunSetDefaults(Scope* scope,
    337                      const FunctionCallNode* function,
    338                      const std::vector<Value>& args,
    339                      BlockNode* block,
    340                      Err* err) {
    341   if (!EnsureSingleStringArg(function, args, err))
    342     return Value();
    343   const std::string& target_type(args[0].string_value());
    344 
    345   // Ensure there aren't defaults already set.
    346   if (scope->GetTargetDefaults(target_type)) {
    347     *err = Err(function->function(),
    348                "This target type defaults were already set.");
    349     return Value();
    350   }
    351 
    352   // Execute the block in a new scope that has a parent of the containing
    353   // scope.
    354   Scope block_scope(scope);
    355   if (!FillTargetBlockScope(scope, function,
    356                             function->function().value().data(),
    357                             block, args, &block_scope, err))
    358     return Value();
    359 
    360   // Run the block for the rule invocation.
    361   block->ExecuteBlockInScope(&block_scope, err);
    362   if (err->has_error())
    363     return Value();
    364 
    365   // Now copy the values set on the scope we made into the free-floating one
    366   // (with no containing scope) used to hold the target defaults.
    367   Scope* dest = scope->MakeTargetDefaults(target_type);
    368   block_scope.NonRecursiveMergeTo(dest, function, "<SHOULD NOT FAIL>", err);
    369   return Value();
    370 }
    371 
    372 // set_sources_assignment_filter -----------------------------------------------
    373 
    374 const char kSetSourcesAssignmentFilter[] = "set_sources_assignment_filter";
    375 const char kSetSourcesAssignmentFilter_Help[] =
    376     "TODO(brettw) write this.";
    377 
    378 Value RunSetSourcesAssignmentFilter(Scope* scope,
    379                                     const FunctionCallNode* function,
    380                                     const std::vector<Value>& args,
    381                                     Err* err) {
    382   if (args.size() != 1) {
    383     *err = Err(function, "set_sources_assignment_filter takes one argument.");
    384   } else {
    385     scoped_ptr<PatternList> f(new PatternList);
    386     f->SetFromValue(args[0], err);
    387     if (!err->has_error())
    388       scope->set_sources_assignment_filter(f.Pass());
    389   }
    390   return Value();
    391 }
    392 
    393 // print -----------------------------------------------------------------------
    394 
    395 const char kPrint[] = "print";
    396 const char kPrint_Help[] =
    397     "print(...)\n"
    398     "  Prints all arguments to the console separated by spaces. A newline is\n"
    399     "  automatically appended to the end.\n"
    400     "\n"
    401     "  This function is intended for debugging. Note that build files are run\n"
    402     "  in parallel so you may get interleaved prints. A buildfile may also\n"
    403     "  be executed more than once in parallel in the context of different\n"
    404     "  toolchains so the prints from one file may be duplicated or\n"
    405     "  interleaved with itself.\n"
    406     "\n"
    407     "Examples:\n"
    408     "  print(\"Hello world\")\n"
    409     "\n"
    410     "  print(sources, deps)\n";
    411 
    412 Value RunPrint(Scope* scope,
    413                const FunctionCallNode* function,
    414                const std::vector<Value>& args,
    415                Err* err) {
    416   for (size_t i = 0; i < args.size(); i++) {
    417     if (i != 0)
    418       std::cout << " ";
    419     std::cout << args[i].ToString();
    420   }
    421   std::cout << std::endl;
    422   return Value();
    423 }
    424 
    425 // -----------------------------------------------------------------------------
    426 
    427 FunctionInfo::FunctionInfo()
    428     : generic_block_runner(NULL),
    429       executed_block_runner(NULL),
    430       no_block_runner(NULL),
    431       help(NULL) {
    432 }
    433 
    434 FunctionInfo::FunctionInfo(GenericBlockFunction gbf, const char* in_help)
    435     : generic_block_runner(gbf),
    436       executed_block_runner(NULL),
    437       no_block_runner(NULL),
    438       help(in_help) {
    439 }
    440 
    441 FunctionInfo::FunctionInfo(ExecutedBlockFunction ebf, const char* in_help)
    442     : generic_block_runner(NULL),
    443       executed_block_runner(ebf),
    444       no_block_runner(NULL),
    445       help(in_help) {
    446 }
    447 
    448 FunctionInfo::FunctionInfo(NoBlockFunction nbf, const char* in_help)
    449     : generic_block_runner(NULL),
    450       executed_block_runner(NULL),
    451       no_block_runner(nbf),
    452       help(in_help) {
    453 }
    454 
    455 // Setup the function map via a static initializer. We use this because it
    456 // avoids race conditions without having to do some global setup function or
    457 // locking-heavy singleton checks at runtime. In practice, we always need this
    458 // before we can do anything interesting, so it's OK to wait for the
    459 // initializer.
    460 struct FunctionInfoInitializer {
    461   FunctionInfoMap map;
    462 
    463   FunctionInfoInitializer() {
    464     #define INSERT_FUNCTION(command) \
    465         map[k##command] = FunctionInfo(&Run##command, k##command##_Help);
    466 
    467     INSERT_FUNCTION(Assert)
    468     INSERT_FUNCTION(Component)
    469     INSERT_FUNCTION(Config)
    470     INSERT_FUNCTION(Copy)
    471     INSERT_FUNCTION(Custom)
    472     INSERT_FUNCTION(DeclareArgs)
    473     INSERT_FUNCTION(ExecScript)
    474     INSERT_FUNCTION(Executable)
    475     INSERT_FUNCTION(Group)
    476     INSERT_FUNCTION(Import)
    477     INSERT_FUNCTION(Print)
    478     INSERT_FUNCTION(ProcessFileTemplate)
    479     INSERT_FUNCTION(ReadFile)
    480     INSERT_FUNCTION(SetDefaults)
    481     INSERT_FUNCTION(SetDefaultToolchain)
    482     INSERT_FUNCTION(SetSourcesAssignmentFilter)
    483     INSERT_FUNCTION(SharedLibrary)
    484     INSERT_FUNCTION(StaticLibrary)
    485     INSERT_FUNCTION(Template)
    486     INSERT_FUNCTION(Test)
    487     INSERT_FUNCTION(Tool)
    488     INSERT_FUNCTION(Toolchain)
    489     INSERT_FUNCTION(WriteFile)
    490 
    491     #undef INSERT_FUNCTION
    492   }
    493 };
    494 const FunctionInfoInitializer function_info;
    495 
    496 const FunctionInfoMap& GetFunctions() {
    497   return function_info.map;
    498 }
    499 
    500 Value RunFunction(Scope* scope,
    501                   const FunctionCallNode* function,
    502                   const std::vector<Value>& args,
    503                   BlockNode* block,
    504                   Err* err) {
    505   const Token& name = function->function();
    506 
    507   const FunctionInfoMap& function_map = GetFunctions();
    508   FunctionInfoMap::const_iterator found_function =
    509       function_map.find(name.value());
    510   if (found_function == function_map.end()) {
    511     // No build-in function matching this, check for a template.
    512     const FunctionCallNode* rule =
    513         scope->GetTemplate(function->function().value().as_string());
    514     if (rule)
    515       return RunTemplateInvocation(scope, function, args, block, rule, err);
    516 
    517     *err = Err(name, "Unknown function.");
    518     return Value();
    519   }
    520 
    521   if (found_function->second.generic_block_runner) {
    522     if (!block) {
    523       FillNeedsBlockError(function, err);
    524       return Value();
    525     }
    526     return found_function->second.generic_block_runner(
    527         scope, function, args, block, err);
    528   }
    529 
    530   if (found_function->second.executed_block_runner) {
    531     if (!block) {
    532       FillNeedsBlockError(function, err);
    533       return Value();
    534     }
    535 
    536     Scope block_scope(scope);
    537     block->ExecuteBlockInScope(&block_scope, err);
    538     if (err->has_error())
    539       return Value();
    540     return found_function->second.executed_block_runner(
    541         function, args, &block_scope, err);
    542   }
    543 
    544   // Otherwise it's a no-block function.
    545   return found_function->second.no_block_runner(scope, function, args, err);
    546 }
    547 
    548 }  // namespace functions
    549