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/target_generator.h"
      6 
      7 #include "tools/gn/action_target_generator.h"
      8 #include "tools/gn/binary_target_generator.h"
      9 #include "tools/gn/build_settings.h"
     10 #include "tools/gn/config.h"
     11 #include "tools/gn/copy_target_generator.h"
     12 #include "tools/gn/err.h"
     13 #include "tools/gn/filesystem_utils.h"
     14 #include "tools/gn/functions.h"
     15 #include "tools/gn/group_target_generator.h"
     16 #include "tools/gn/parse_tree.h"
     17 #include "tools/gn/scheduler.h"
     18 #include "tools/gn/scope.h"
     19 #include "tools/gn/token.h"
     20 #include "tools/gn/value.h"
     21 #include "tools/gn/value_extractors.h"
     22 #include "tools/gn/variables.h"
     23 
     24 TargetGenerator::TargetGenerator(Target* target,
     25                                  Scope* scope,
     26                                  const FunctionCallNode* function_call,
     27                                  Err* err)
     28     : target_(target),
     29       scope_(scope),
     30       function_call_(function_call),
     31       err_(err) {
     32 }
     33 
     34 TargetGenerator::~TargetGenerator() {
     35 }
     36 
     37 void TargetGenerator::Run() {
     38   // All target types use these.
     39   if (!FillDependentConfigs())
     40     return;
     41 
     42   if (!FillData())
     43     return;
     44 
     45   if (!FillDependencies())
     46     return;
     47 
     48   if (!FillTestonly())
     49     return;
     50 
     51   if (!Visibility::FillItemVisibility(target_, scope_, err_))
     52     return;
     53 
     54   // Do type-specific generation.
     55   DoRun();
     56 }
     57 
     58 // static
     59 void TargetGenerator::GenerateTarget(Scope* scope,
     60                                      const FunctionCallNode* function_call,
     61                                      const std::vector<Value>& args,
     62                                      const std::string& output_type,
     63                                      Err* err) {
     64   // Name is the argument to the function.
     65   if (args.size() != 1u || args[0].type() != Value::STRING) {
     66     *err = Err(function_call,
     67         "Target generator requires one string argument.",
     68         "Otherwise I'm not sure what to call this target.");
     69     return;
     70   }
     71 
     72   // The location of the target is the directory name with no slash at the end.
     73   // FIXME(brettw) validate name.
     74   const Label& toolchain_label = ToolchainLabelForScope(scope);
     75   Label label(scope->GetSourceDir(), args[0].string_value(),
     76               toolchain_label.dir(), toolchain_label.name());
     77 
     78   if (g_scheduler->verbose_logging())
     79     g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
     80 
     81   scoped_ptr<Target> target(new Target(scope->settings(), label));
     82   target->set_defined_from(function_call);
     83 
     84   // Create and call out to the proper generator.
     85   if (output_type == functions::kCopy) {
     86     CopyTargetGenerator generator(target.get(), scope, function_call, err);
     87     generator.Run();
     88   } else if (output_type == functions::kAction) {
     89     ActionTargetGenerator generator(target.get(), scope, function_call,
     90                                     Target::ACTION, err);
     91     generator.Run();
     92   } else if (output_type == functions::kActionForEach) {
     93     ActionTargetGenerator generator(target.get(), scope, function_call,
     94                                     Target::ACTION_FOREACH, err);
     95     generator.Run();
     96   } else if (output_type == functions::kExecutable) {
     97     BinaryTargetGenerator generator(target.get(), scope, function_call,
     98                                     Target::EXECUTABLE, err);
     99     generator.Run();
    100   } else if (output_type == functions::kGroup) {
    101     GroupTargetGenerator generator(target.get(), scope, function_call, err);
    102     generator.Run();
    103   } else if (output_type == functions::kSharedLibrary) {
    104     BinaryTargetGenerator generator(target.get(), scope, function_call,
    105                                     Target::SHARED_LIBRARY, err);
    106     generator.Run();
    107   } else if (output_type == functions::kSourceSet) {
    108     BinaryTargetGenerator generator(target.get(), scope, function_call,
    109                                     Target::SOURCE_SET, err);
    110     generator.Run();
    111   } else if (output_type == functions::kStaticLibrary) {
    112     BinaryTargetGenerator generator(target.get(), scope, function_call,
    113                                     Target::STATIC_LIBRARY, err);
    114     generator.Run();
    115   } else {
    116     *err = Err(function_call, "Not a known output type",
    117                "I am very confused.");
    118   }
    119 
    120   if (err->has_error())
    121     return;
    122 
    123   // Save this target for the file.
    124   Scope::ItemVector* collector = scope->GetItemCollector();
    125   if (!collector) {
    126     *err = Err(function_call, "Can't define a target in this context.");
    127     return;
    128   }
    129   collector->push_back(new scoped_ptr<Item>(target.PassAs<Item>()));
    130 }
    131 
    132 const BuildSettings* TargetGenerator::GetBuildSettings() const {
    133   return scope_->settings()->build_settings();
    134 }
    135 
    136 bool TargetGenerator::FillSources() {
    137   const Value* value = scope_->GetValue(variables::kSources, true);
    138   if (!value)
    139     return true;
    140 
    141   Target::FileList dest_sources;
    142   if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
    143                                   scope_->GetSourceDir(), &dest_sources, err_))
    144     return false;
    145   target_->sources().swap(dest_sources);
    146   return true;
    147 }
    148 
    149 bool TargetGenerator::FillPublic() {
    150   const Value* value = scope_->GetValue(variables::kPublic, true);
    151   if (!value)
    152     return true;
    153 
    154   // If the public headers are defined, don't default to public.
    155   target_->set_all_headers_public(false);
    156 
    157   Target::FileList dest_public;
    158   if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
    159                                   scope_->GetSourceDir(), &dest_public, err_))
    160     return false;
    161   target_->public_headers().swap(dest_public);
    162   return true;
    163 }
    164 
    165 bool TargetGenerator::FillInputs() {
    166   const Value* value = scope_->GetValue(variables::kInputs, true);
    167  if (!value) {
    168     // Older versions used "source_prereqs". Allow use of this variable until
    169     // all callers are updated.
    170     // TODO(brettw) remove this eventually.
    171     value = scope_->GetValue("source_prereqs", true);
    172     if (!value)
    173       return true;
    174   }
    175 
    176   Target::FileList dest_inputs;
    177   if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
    178                                   scope_->GetSourceDir(), &dest_inputs, err_))
    179     return false;
    180   target_->inputs().swap(dest_inputs);
    181   return true;
    182 }
    183 
    184 bool TargetGenerator::FillConfigs() {
    185   return FillGenericConfigs(variables::kConfigs, &target_->configs());
    186 }
    187 
    188 bool TargetGenerator::FillDependentConfigs() {
    189   if (!FillGenericConfigs(variables::kAllDependentConfigs,
    190                           &target_->all_dependent_configs()))
    191     return false;
    192   if (!FillGenericConfigs(variables::kPublicConfigs,
    193                           &target_->public_configs()))
    194     return false;
    195 
    196   // "public_configs" was previously named "direct_dependent_configs", fall
    197   // back to that if public_configs was undefined.
    198   if (!scope_->GetValue(variables::kPublicConfigs, false)) {
    199     if (!FillGenericConfigs("direct_dependent_configs",
    200                             &target_->public_configs()))
    201       return false;
    202   }
    203   return true;
    204 }
    205 
    206 bool TargetGenerator::FillData() {
    207   const Value* value = scope_->GetValue(variables::kData, true);
    208   if (!value)
    209     return true;
    210 
    211   Target::FileList dest_data;
    212   if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
    213                                   scope_->GetSourceDir(), &dest_data, err_))
    214     return false;
    215   target_->data().swap(dest_data);
    216   return true;
    217 }
    218 
    219 bool TargetGenerator::FillDependencies() {
    220   if (!FillGenericDeps(variables::kDeps, &target_->private_deps()))
    221     return false;
    222   if (!FillGenericDeps(variables::kPublicDeps, &target_->public_deps()))
    223     return false;
    224   if (!FillGenericDeps(variables::kDataDeps, &target_->data_deps()))
    225     return false;
    226 
    227   // "data_deps" was previously named "datadeps". For backwards-compat, read
    228   // the old one if no "data_deps" were specified.
    229   if (!scope_->GetValue(variables::kDataDeps, false)) {
    230     if (!FillGenericDeps("datadeps", &target_->data_deps()))
    231       return false;
    232   }
    233 
    234   // This is a list of dependent targets to have their configs fowarded, so
    235   // it goes here rather than in FillConfigs.
    236   if (!FillForwardDependentConfigs())
    237     return false;
    238   return true;
    239 }
    240 
    241 bool TargetGenerator::FillTestonly() {
    242   const Value* value = scope_->GetValue(variables::kTestonly, true);
    243   if (value) {
    244     if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
    245       return false;
    246     target_->set_testonly(value->boolean_value());
    247   }
    248   return true;
    249 }
    250 
    251 bool TargetGenerator::FillOutputs(bool allow_substitutions) {
    252   const Value* value = scope_->GetValue(variables::kOutputs, true);
    253   if (!value)
    254     return true;
    255 
    256   SubstitutionList& outputs = target_->action_values().outputs();
    257   if (!outputs.Parse(*value, err_))
    258     return false;
    259 
    260   if (!allow_substitutions) {
    261     // Verify no substitutions were actually used.
    262     if (!outputs.required_types().empty()) {
    263       *err_ = Err(*value, "Source expansions not allowed here.",
    264           "The outputs of this target used source {{expansions}} but this "
    265           "targe type\ndoesn't support them. Just express the outputs "
    266           "literally.");
    267       return false;
    268     }
    269   }
    270 
    271   // Check the substitutions used are valid for this purpose.
    272   if (!EnsureValidSourcesSubstitutions(outputs.required_types(),
    273                                        value->origin(), err_))
    274     return false;
    275 
    276   // Validate that outputs are in the output dir.
    277   CHECK(outputs.list().size() == value->list_value().size());
    278   for (size_t i = 0; i < outputs.list().size(); i++) {
    279     if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i],
    280                                          value->list_value()[i]))
    281       return false;
    282   }
    283   return true;
    284 }
    285 
    286 bool TargetGenerator::EnsureSubstitutionIsInOutputDir(
    287     const SubstitutionPattern& pattern,
    288     const Value& original_value) {
    289   if (pattern.ranges().empty()) {
    290     // Pattern is empty, error out (this prevents weirdness below).
    291     *err_ = Err(original_value, "This has an empty value in it.");
    292     return false;
    293   }
    294 
    295   if (pattern.ranges()[0].type == SUBSTITUTION_LITERAL) {
    296     // If the first thing is a literal, it must start with the output dir.
    297     if (!EnsureStringIsInOutputDir(
    298             GetBuildSettings()->build_dir(),
    299             pattern.ranges()[0].literal, original_value.origin(), err_))
    300       return false;
    301   } else {
    302     // Otherwise, the first subrange must be a pattern that expands to
    303     // something in the output directory.
    304     if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) {
    305       *err_ = Err(original_value,
    306           "File is not inside output directory.",
    307           "The given file should be in the output directory. Normally you\n"
    308           "would specify\n\"$target_out_dir/foo\" or "
    309           "\"{{source_gen_dir}}/foo\".");
    310       return false;
    311     }
    312   }
    313 
    314   return true;
    315 }
    316 
    317 bool TargetGenerator::FillGenericConfigs(const char* var_name,
    318                                          UniqueVector<LabelConfigPair>* dest) {
    319   const Value* value = scope_->GetValue(var_name, true);
    320   if (value) {
    321     ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(),
    322                               ToolchainLabelForScope(scope_), dest, err_);
    323   }
    324   return !err_->has_error();
    325 }
    326 
    327 bool TargetGenerator::FillGenericDeps(const char* var_name,
    328                                       LabelTargetVector* dest) {
    329   const Value* value = scope_->GetValue(var_name, true);
    330   if (value) {
    331     ExtractListOfLabels(*value, scope_->GetSourceDir(),
    332                         ToolchainLabelForScope(scope_), dest, err_);
    333   }
    334   return !err_->has_error();
    335 }
    336 
    337 bool TargetGenerator::FillForwardDependentConfigs() {
    338   const Value* value = scope_->GetValue(
    339       variables::kForwardDependentConfigsFrom, true);
    340   if (value) {
    341     ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(),
    342                               ToolchainLabelForScope(scope_),
    343                               &target_->forward_dependent_configs(), err_);
    344   }
    345   return !err_->has_error();
    346 }
    347