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_manager.h"
      6 
      7 #include <deque>
      8 
      9 #include "base/bind.h"
     10 #include "base/strings/string_piece.h"
     11 #include "tools/gn/build_settings.h"
     12 #include "tools/gn/err.h"
     13 #include "tools/gn/filesystem_utils.h"
     14 #include "tools/gn/item_node.h"
     15 #include "tools/gn/scheduler.h"
     16 #include "tools/gn/toolchain_manager.h"
     17 #include "tools/gn/value.h"
     18 
     19 TargetManager::TargetManager(const BuildSettings* build_settings)
     20     : build_settings_(build_settings) {
     21 }
     22 
     23 TargetManager::~TargetManager() {
     24 }
     25 
     26 Target* TargetManager::GetTarget(const Label& label,
     27                                  const LocationRange& specified_from_here,
     28                                  Target* dep_from,
     29                                  Err* err) {
     30   DCHECK(!label.is_null());
     31   DCHECK(!label.toolchain_dir().value().empty());
     32   DCHECK(!label.toolchain_name().empty());
     33 
     34   base::AutoLock lock(build_settings_->item_tree().lock());
     35 
     36   ItemNode* target_node =
     37       build_settings_->item_tree().GetExistingNodeLocked(label);
     38   Target* target = NULL;
     39   if (!target_node) {
     40     // First time we've seen this, may need to load the file.
     41 
     42     // Compute the settings. The common case is that we have a dep_from and
     43     // the toolchains match, so we can use the settings from there rather than
     44     // querying the toolchain manager (which requires locking, etc.).
     45     const Settings* settings;
     46     if (dep_from && dep_from->label().ToolchainsEqual(label)) {
     47       settings = dep_from->settings();
     48     } else {
     49       settings =
     50           build_settings_->toolchain_manager().GetSettingsForToolchainLocked(
     51               specified_from_here, label.GetToolchainLabel(), err);
     52       if (!settings)
     53         return NULL;
     54     }
     55 
     56     target = new Target(settings, label);
     57 
     58     target_node = new ItemNode(target);
     59     if (settings->greedy_target_generation()) {
     60       if (!target_node->SetShouldGenerate(build_settings_, err))
     61         return NULL;
     62     }
     63     target_node->set_originally_referenced_from_here(specified_from_here);
     64 
     65     build_settings_->item_tree().AddNodeLocked(target_node);
     66 
     67     // We're generating a node when there is no referencing one.
     68     if (!dep_from)
     69       target_node->set_generated_from_here(specified_from_here);
     70 
     71   } else if ((target = target_node->item()->AsTarget())) {
     72     // Previously saw this item as a target.
     73 
     74     // If we have no dep_from, we're generating it.
     75     if (!dep_from) {
     76       // In this case, it had better not already be generated.
     77       if (target_node->state() != ItemNode::REFERENCED) {
     78         *err = Err(specified_from_here,
     79                    "Duplicate target.",
     80                    "\"" + label.GetUserVisibleName(true) +
     81                    "\" being defined here.");
     82         err->AppendSubErr(Err(target_node->generated_from_here(),
     83                               "Originally defined here."));
     84         return NULL;
     85       } else {
     86         target_node->set_generated_from_here(specified_from_here);
     87       }
     88     }
     89   } else {
     90     // Error, we previously saw this thing as a non-target.
     91     *err = Err(specified_from_here, "Not previously a target.",
     92         "The target being declared here was previously seen referenced as a\n"
     93         "non-target (like a config)");
     94     err->AppendSubErr(Err(target_node->originally_referenced_from_here(),
     95                           "Originally referenced from here."));
     96     return NULL;
     97   }
     98 
     99   // Keep a record of the guy asking us for this dependency. We know if
    100   // somebody is adding a dependency, that guy it himself not resolved.
    101   if (dep_from && target_node->state() != ItemNode::RESOLVED) {
    102     ItemNode* from_node =
    103         build_settings_->item_tree().GetExistingNodeLocked(dep_from->label());
    104     if (!from_node->AddDependency(build_settings_, specified_from_here,
    105                                   target_node, err))
    106       return NULL;
    107   }
    108 
    109   return target;
    110 }
    111 
    112 bool TargetManager::TargetGenerationComplete(const Label& label,
    113                                              Err* err) {
    114   base::AutoLock lock(build_settings_->item_tree().lock());
    115   return build_settings_->item_tree().MarkItemDefinedLocked(
    116       build_settings_, label, err);
    117 }
    118 
    119 void TargetManager::GetAllTargets(
    120     std::vector<const Target*>* all_targets) const {
    121   base::AutoLock lock(build_settings_->item_tree().lock());
    122 
    123   std::vector<const Item*> all_items;
    124   build_settings_->item_tree().GetAllItemsLocked(&all_items);
    125   for (size_t i = 0; i < all_items.size(); i++) {
    126     const Target* t = all_items[i]->AsTarget();
    127     if (t)
    128       all_targets->push_back(t);
    129   }
    130 }
    131