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/action_target_generator.h"
      6 
      7 #include "tools/gn/build_settings.h"
      8 #include "tools/gn/err.h"
      9 #include "tools/gn/filesystem_utils.h"
     10 #include "tools/gn/parse_tree.h"
     11 #include "tools/gn/scope.h"
     12 #include "tools/gn/value.h"
     13 #include "tools/gn/value_extractors.h"
     14 #include "tools/gn/variables.h"
     15 
     16 ActionTargetGenerator::ActionTargetGenerator(
     17     Target* target,
     18     Scope* scope,
     19     const FunctionCallNode* function_call,
     20     Target::OutputType type,
     21     Err* err)
     22     : TargetGenerator(target, scope, function_call, err),
     23       output_type_(type) {
     24 }
     25 
     26 ActionTargetGenerator::~ActionTargetGenerator() {
     27 }
     28 
     29 void ActionTargetGenerator::DoRun() {
     30   target_->set_output_type(output_type_);
     31 
     32   if (!FillSources())
     33     return;
     34   if (output_type_ == Target::ACTION_FOREACH && target_->sources().empty()) {
     35     // Foreach rules must always have some sources to have an effect.
     36     *err_ = Err(function_call_, "action_foreach target has no sources.",
     37         "If you don't specify any sources, there is nothing to run your\n"
     38         "script over.");
     39     return;
     40   }
     41 
     42   if (!FillInputs())
     43     return;
     44 
     45   if (!FillScript())
     46     return;
     47 
     48   if (!FillScriptArgs())
     49     return;
     50 
     51   if (!FillOutputs(output_type_ == Target::ACTION_FOREACH))
     52     return;
     53 
     54   if (!FillDepfile())
     55     return;
     56 
     57   if (!CheckOutputs())
     58     return;
     59 
     60   // Action outputs don't depend on the current toolchain so we can skip adding
     61   // that dependency.
     62 }
     63 
     64 bool ActionTargetGenerator::FillScript() {
     65   // If this gets called, the target type requires a script, so error out
     66   // if it doesn't have one.
     67   const Value* value = scope_->GetValue(variables::kScript, true);
     68   if (!value) {
     69     *err_ = Err(function_call_, "This target type requires a \"script\".");
     70     return false;
     71   }
     72   if (!value->VerifyTypeIs(Value::STRING, err_))
     73     return false;
     74 
     75   SourceFile script_file =
     76       scope_->GetSourceDir().ResolveRelativeFile(value->string_value());
     77   if (script_file.value().empty()) {
     78     *err_ = Err(*value, "script name is empty");
     79     return false;
     80   }
     81   target_->action_values().set_script(script_file);
     82   return true;
     83 }
     84 
     85 bool ActionTargetGenerator::FillScriptArgs() {
     86   const Value* value = scope_->GetValue(variables::kArgs, true);
     87   if (!value)
     88     return true;
     89   return target_->action_values().args().Parse(*value, err_);
     90 }
     91 
     92 bool ActionTargetGenerator::FillDepfile() {
     93   const Value* value = scope_->GetValue(variables::kDepfile, true);
     94   if (!value)
     95     return true;
     96 
     97   SubstitutionPattern depfile;
     98   if (!depfile.Parse(*value, err_))
     99     return false;
    100   if (!EnsureSubstitutionIsInOutputDir(depfile, *value))
    101     return false;
    102 
    103   target_->action_values().set_depfile(depfile);
    104   return true;
    105 }
    106 
    107 bool ActionTargetGenerator::CheckOutputs() {
    108   const SubstitutionList& outputs = target_->action_values().outputs();
    109   if (outputs.list().empty()) {
    110     *err_ = Err(function_call_, "Action has no outputs.",
    111         "If you have no outputs, the build system can not tell when your\n"
    112         "script needs to be run.");
    113     return false;
    114   }
    115 
    116   if (output_type_ == Target::ACTION) {
    117     if (!outputs.required_types().empty()) {
    118       *err_ = Err(function_call_, "Action has patterns in the output.",
    119           "An action target should have the outputs completely specified. If\n"
    120           "you want to provide a mapping from source to output, use an\n"
    121           "\"action_foreach\" target.");
    122       return false;
    123     }
    124   } else if (output_type_ == Target::ACTION_FOREACH) {
    125     // A foreach target should always have a pattern in the outputs.
    126     if (outputs.required_types().empty()) {
    127       *err_ = Err(function_call_,
    128           "action_foreach should have a pattern in the output.",
    129           "An action_foreach target should have a source expansion pattern in\n"
    130           "it to map source file to unique output file name. Otherwise, the\n"
    131           "build system can't determine when your script needs to be run.");
    132       return false;
    133     }
    134   }
    135   return true;
    136 }
    137