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 "base/files/file_path.h"
      8 #include "base/logging.h"
      9 #include "tools/gn/build_settings.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/filesystem_utils.h"
     14 #include "tools/gn/functions.h"
     15 #include "tools/gn/input_file.h"
     16 #include "tools/gn/item_node.h"
     17 #include "tools/gn/ninja_target_writer.h"
     18 #include "tools/gn/parse_tree.h"
     19 #include "tools/gn/scheduler.h"
     20 #include "tools/gn/scope.h"
     21 #include "tools/gn/target_manager.h"
     22 #include "tools/gn/token.h"
     23 #include "tools/gn/value.h"
     24 #include "tools/gn/value_extractors.h"
     25 #include "tools/gn/variables.h"
     26 
     27 namespace {
     28 
     29 bool TypeHasConfigs(Target::OutputType type) {
     30   return type == Target::EXECUTABLE ||
     31          type == Target::SHARED_LIBRARY ||
     32          type == Target::STATIC_LIBRARY ||
     33          type == Target::LOADABLE_MODULE;
     34 }
     35 
     36 bool TypeHasConfigValues(Target::OutputType type) {
     37   return type == Target::EXECUTABLE ||
     38          type == Target::SHARED_LIBRARY ||
     39          type == Target::STATIC_LIBRARY ||
     40          type == Target::LOADABLE_MODULE;
     41 }
     42 
     43 bool TypeHasSources(Target::OutputType type) {
     44   return type != Target::NONE;
     45 }
     46 
     47 bool TypeHasData(Target::OutputType type) {
     48   return type != Target::NONE;
     49 }
     50 
     51 bool TypeHasDestDir(Target::OutputType type) {
     52   return type == Target::COPY_FILES;
     53 }
     54 
     55 bool TypeHasOutputs(Target::OutputType type) {
     56   return type == Target::CUSTOM;
     57 }
     58 
     59 }  // namespace
     60 
     61 TargetGenerator::TargetGenerator(Target* target,
     62                                  Scope* scope,
     63                                  const Token& function_token,
     64                                  const std::vector<Value>& args,
     65                                  const std::string& output_type,
     66                                  Err* err)
     67     : target_(target),
     68       scope_(scope),
     69       function_token_(function_token),
     70       args_(args),
     71       output_type_(output_type),
     72       err_(err),
     73       input_directory_(function_token.location().file()->dir()) {
     74 }
     75 
     76 TargetGenerator::~TargetGenerator() {
     77 }
     78 
     79 void TargetGenerator::Run() {
     80   // Output type.
     81   Target::OutputType output_type = GetOutputType();
     82   target_->set_output_type(output_type);
     83   if (err_->has_error())
     84     return;
     85 
     86   if (TypeHasConfigs(output_type)) {
     87     FillConfigs();
     88     FillAllDependentConfigs();
     89     FillDirectDependentConfigs();
     90   }
     91   if (TypeHasSources(output_type))
     92     FillSources();
     93   if (TypeHasData(output_type))
     94     FillData();
     95   if (output_type == Target::CUSTOM) {
     96     FillScript();
     97     FillScriptArgs();
     98   }
     99   if (TypeHasOutputs(output_type))
    100     FillOutputs();
    101   FillDependencies();  // All types have dependencies.
    102   FillDataDependencies();  // All types have dependencies.
    103 
    104   if (TypeHasConfigValues(output_type)) {
    105     ConfigValuesGenerator gen(&target_->config_values(), scope_,
    106                               function_token_, input_directory_, err_);
    107     gen.Run();
    108     if (err_->has_error())
    109       return;
    110   }
    111 
    112   if (TypeHasDestDir(output_type))
    113     FillDestDir();
    114 
    115   // Set the toolchain as a dependency of the target.
    116   // TODO(brettw) currently we lock separately for each config, dep, and
    117   // toolchain we add which is bad! Do this in one lock.
    118   {
    119     ItemTree* tree = &GetBuildSettings()->item_tree();
    120     base::AutoLock lock(tree->lock());
    121     ItemNode* tc_node =
    122         tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_));
    123     if (!tree->GetExistingNodeLocked(target_->label())->AddDependency(
    124             GetBuildSettings(), function_token_.range(), tc_node, err_))
    125       return;
    126   }
    127 
    128   target_->SetGenerated(&function_token_);
    129   GetBuildSettings()->target_manager().TargetGenerationComplete(
    130       target_->label(), err_);
    131 }
    132 
    133 // static
    134 void TargetGenerator::GenerateTarget(Scope* scope,
    135                                      const Token& function_token,
    136                                      const std::vector<Value>& args,
    137                                      const std::string& output_type,
    138                                      Err* err) {
    139   // Name is the argument to the function.
    140   if (args.size() != 1u || args[0].type() != Value::STRING) {
    141     *err = Err(function_token,
    142         "Target generator requires one string argument.",
    143         "Otherwise I'm not sure what to call this target.");
    144     return;
    145   }
    146 
    147   // The location of the target is the directory name with no slash at the end.
    148   // FIXME(brettw) validate name.
    149   const Label& toolchain_label = ToolchainLabelForScope(scope);
    150   Label label(function_token.location().file()->dir(),
    151               args[0].string_value(),
    152               toolchain_label.dir(), toolchain_label.name());
    153 
    154   if (g_scheduler->verbose_logging())
    155     g_scheduler->Log("Generating target", label.GetUserVisibleName(true));
    156 
    157   Target* t = scope->settings()->build_settings()->target_manager().GetTarget(
    158       label, function_token.range(), NULL, err);
    159   if (err->has_error())
    160     return;
    161 
    162   TargetGenerator gen(t, scope, function_token, args, output_type, err);
    163   gen.Run();
    164 }
    165 
    166 Target::OutputType TargetGenerator::GetOutputType() const {
    167   if (output_type_ == functions::kGroup)
    168     return Target::NONE;
    169   if (output_type_ == functions::kExecutable)
    170     return Target::EXECUTABLE;
    171   if (output_type_ == functions::kSharedLibrary)
    172     return Target::SHARED_LIBRARY;
    173   if (output_type_ == functions::kStaticLibrary)
    174     return Target::STATIC_LIBRARY;
    175   // TODO(brettw) what does loadable module mean?
    176   //if (output_type_ == ???)
    177   //  return Target::LOADABLE_MODULE;
    178   if (output_type_ == functions::kCopy)
    179     return Target::COPY_FILES;
    180   if (output_type_ == functions::kCustom)
    181     return Target::CUSTOM;
    182 
    183   *err_ = Err(function_token_, "Not a known output type",
    184               "I am very confused.");
    185   return Target::NONE;
    186 }
    187 
    188 void TargetGenerator::FillGenericConfigs(
    189     const char* var_name,
    190     void (Target::*setter)(std::vector<const Config*>*)) {
    191   const Value* value = scope_->GetValue(var_name, true);
    192   if (!value)
    193     return;
    194 
    195   std::vector<Label> labels;
    196   if (!ExtractListOfLabels(*value, input_directory_,
    197                            ToolchainLabelForScope(scope_), &labels, err_))
    198     return;
    199 
    200   std::vector<const Config*> dest_configs;
    201   dest_configs.resize(labels.size());
    202   for (size_t i = 0; i < labels.size(); i++) {
    203     dest_configs[i] = Config::GetConfig(
    204         scope_->settings(),
    205         value->list_value()[i].origin()->GetRange(),
    206         labels[i], target_, err_);
    207     if (err_->has_error())
    208       return;
    209   }
    210   (target_->*setter)(&dest_configs);
    211 }
    212 
    213 void TargetGenerator::FillGenericDeps(
    214     const char* var_name,
    215     void (Target::*setter)(std::vector<const Target*>*)) {
    216   const Value* value = scope_->GetValue(var_name, true);
    217   if (!value)
    218     return;
    219 
    220   std::vector<Label> labels;
    221   if (!ExtractListOfLabels(*value, input_directory_,
    222                            ToolchainLabelForScope(scope_), &labels, err_))
    223     return;
    224 
    225   std::vector<const Target*> dest_deps;
    226   dest_deps.resize(labels.size());
    227   for (size_t i = 0; i < labels.size(); i++) {
    228     dest_deps[i] = GetBuildSettings()->target_manager().GetTarget(
    229         labels[i], value->list_value()[i].origin()->GetRange(), target_, err_);
    230     if (err_->has_error())
    231       return;
    232   }
    233 
    234   (target_->*setter)(&dest_deps);
    235 }
    236 
    237 void TargetGenerator::FillConfigs() {
    238   FillGenericConfigs(variables::kConfigs, &Target::swap_in_configs);
    239 }
    240 
    241 void TargetGenerator::FillAllDependentConfigs() {
    242   FillGenericConfigs(variables::kAllDependentConfigs,
    243                      &Target::swap_in_all_dependent_configs);
    244 }
    245 
    246 void TargetGenerator::FillDirectDependentConfigs() {
    247   FillGenericConfigs(variables::kDirectDependentConfigs,
    248                      &Target::swap_in_direct_dependent_configs);
    249 }
    250 
    251 void TargetGenerator::FillSources() {
    252   const Value* value = scope_->GetValue(variables::kSources, true);
    253   if (!value)
    254     return;
    255 
    256   Target::FileList dest_sources;
    257   if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_sources,
    258                                   err_))
    259     return;
    260   target_->swap_in_sources(&dest_sources);
    261 }
    262 
    263 void TargetGenerator::FillData() {
    264   // TODO(brettW) hook this up to the constant when we have cleaned up
    265   // how data files are used.
    266   const Value* value = scope_->GetValue("data", true);
    267   if (!value)
    268     return;
    269 
    270   Target::FileList dest_data;
    271   if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_data,
    272                                   err_))
    273     return;
    274   target_->swap_in_data(&dest_data);
    275 }
    276 
    277 void TargetGenerator::FillDependencies() {
    278   FillGenericDeps(variables::kDeps, &Target::swap_in_deps);
    279 }
    280 
    281 void TargetGenerator::FillDataDependencies() {
    282   FillGenericDeps(variables::kDatadeps, &Target::swap_in_datadeps);
    283 }
    284 
    285 void TargetGenerator::FillDestDir() {
    286   // Destdir is required for all targets that use it.
    287   const Value* value = scope_->GetValue("destdir", true);
    288   if (!value) {
    289     *err_ = Err(function_token_, "This target type requires a \"destdir\".");
    290     return;
    291   }
    292   if (!value->VerifyTypeIs(Value::STRING, err_))
    293     return;
    294 
    295   if (!EnsureStringIsInOutputDir(
    296           GetBuildSettings()->build_dir(),
    297           value->string_value(), *value, err_))
    298     return;
    299   target_->set_destdir(SourceDir(value->string_value()));
    300 }
    301 
    302 void TargetGenerator::FillScript() {
    303   // If this gets called, the target type requires a script, so error out
    304   // if it doesn't have one.
    305   const Value* value = scope_->GetValue("script", true);
    306   if (!value) {
    307     *err_ = Err(function_token_, "This target type requires a \"script\".");
    308     return;
    309   }
    310   if (!value->VerifyTypeIs(Value::STRING, err_))
    311     return;
    312 
    313   target_->set_script(
    314       input_directory_.ResolveRelativeFile(value->string_value()));
    315 }
    316 
    317 void TargetGenerator::FillScriptArgs() {
    318   const Value* value = scope_->GetValue("args", true);
    319   if (!value)
    320     return;
    321 
    322   std::vector<std::string> args;
    323   if (!ExtractListOfStringValues(*value, &args, err_))
    324     return;
    325   target_->swap_in_script_args(&args);
    326 }
    327 
    328 void TargetGenerator::FillOutputs() {
    329   const Value* value = scope_->GetValue("outputs", true);
    330   if (!value)
    331     return;
    332 
    333   Target::FileList outputs;
    334   if (!ExtractListOfRelativeFiles(*value, input_directory_, &outputs, err_))
    335     return;
    336 
    337   // Validate that outputs are in the output dir.
    338   CHECK(outputs.size() == value->list_value().size());
    339   for (size_t i = 0; i < outputs.size(); i++) {
    340     if (!EnsureStringIsInOutputDir(
    341             GetBuildSettings()->build_dir(),
    342             outputs[i].value(), value->list_value()[i], err_))
    343       return;
    344   }
    345   target_->swap_in_outputs(&outputs);
    346 }
    347 
    348 const BuildSettings* TargetGenerator::GetBuildSettings() const {
    349   return scope_->settings()->build_settings();
    350 }
    351