diff options
Diffstat (limited to 'tools/gn/target_manager.cc')
-rw-r--r-- | tools/gn/target_manager.cc | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/tools/gn/target_manager.cc b/tools/gn/target_manager.cc new file mode 100644 index 0000000..ece9f08 --- /dev/null +++ b/tools/gn/target_manager.cc @@ -0,0 +1,134 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/gn/target_manager.h" + +#include <deque> + +#include "base/bind.h" +#include "base/strings/string_piece.h" +#include "tools/gn/build_settings.h" +#include "tools/gn/err.h" +#include "tools/gn/filesystem_utils.h" +#include "tools/gn/item_node.h" +#include "tools/gn/scheduler.h" +#include "tools/gn/toolchain_manager.h" +#include "tools/gn/value.h" + +TargetManager::TargetManager(const BuildSettings* build_settings) + : build_settings_(build_settings) { +} + +TargetManager::~TargetManager() { +} + +Target* TargetManager::GetTarget(const Label& label, + const LocationRange& specified_from_here, + Target* dep_from, + Err* err) { + DCHECK(!label.is_null()); + DCHECK(!label.toolchain_dir().value().empty()); + DCHECK(!label.toolchain_name().empty()); + + base::AutoLock lock(build_settings_->item_tree().lock()); + + ItemNode* target_node = + build_settings_->item_tree().GetExistingNodeLocked(label); + Target* target = NULL; + if (!target_node) { + // First time we've seen this, may need to load the file. + + // Compute the settings. The common case is that we have a dep_from and + // the toolchains match, so we can use the settings from there rather than + // querying the toolchain manager (which requires locking, etc.). + const Settings* settings; + if (dep_from && dep_from->label().ToolchainsEqual(label)) { + settings = dep_from->settings(); + } else { + settings = + build_settings_->toolchain_manager().GetSettingsForToolchainLocked( + specified_from_here, label.GetToolchainLabel(), err); + if (!settings) + return NULL; + } + + target = new Target(settings, label); + target_node = new ItemNode(target); + target_node->set_originally_referenced_from_here(specified_from_here); + build_settings_->item_tree().AddNodeLocked(target_node); + + // We're generating a node when there is no referencing one. + if (!dep_from) + target_node->set_generated_from_here(specified_from_here); + + // Only schedule loading the given target if somebody is depending on it + // (and we optimize by not re-asking it to run the current file). + // Otherwise, we're probably generating it right now. + if (dep_from && dep_from->label().dir() != label.dir()) { + if (!ScheduleInvocationLocked(specified_from_here, label, err)) + return NULL; + } + } else if ((target = target_node->item()->AsTarget())) { + // Previously saw this item as a target. + + // If we have no dep_from, we're generating it. + if (!dep_from) { + // In this case, it had better not already be generated. + if (target_node->state() != ItemNode::REFERENCED) { + *err = Err(specified_from_here, + "Duplicate target.", + "\"" + label.GetUserVisibleName(true) + + "\" being defined here."); + err->AppendSubErr(Err(target_node->generated_from_here(), + "Originally defined here.")); + return NULL; + } else { + target_node->set_generated_from_here(specified_from_here); + } + } + } else { + // Error, we previously saw this thing as a non-target. + *err = Err(specified_from_here, "Not previously a target.", + "The target being declared here was previously seen referenced as a\n" + "non-target (like a config)"); + err->AppendSubErr(Err(target_node->originally_referenced_from_here(), + "Originally referenced from here.")); + return NULL; + } + + // Keep a record of the guy asking us for this dependency. We know if + // somebody is adding a dependency, that guy it himself not resolved. + if (dep_from && target_node->state() != ItemNode::RESOLVED) { + build_settings_->item_tree().GetExistingNodeLocked( + dep_from->label())->AddDependency(target_node); + } + + return target; +} + +void TargetManager::TargetGenerationComplete(const Label& label) { + base::AutoLock lock(build_settings_->item_tree().lock()); + build_settings_->item_tree().MarkItemGeneratedLocked(label); +} + +void TargetManager::GetAllTargets( + std::vector<const Target*>* all_targets) const { + base::AutoLock lock(build_settings_->item_tree().lock()); + + std::vector<const Item*> all_items; + build_settings_->item_tree().GetAllItemsLocked(&all_items); + for (size_t i = 0; i < all_items.size(); i++) { + const Target* t = all_items[i]->AsTarget(); + if (t) + all_targets->push_back(t); + } +} + +bool TargetManager::ScheduleInvocationLocked( + const LocationRange& specified_from_here, + const Label& label, + Err* err) { + return build_settings_->toolchain_manager().ScheduleInvocationLocked( + specified_from_here, label.GetToolchainLabel(), label.dir(), err); +} |