// 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/item_node.h" #include #include "base/callback.h" #include "base/logging.h" #include "tools/gn/build_settings.h" #include "tools/gn/item.h" ItemNode::ItemNode(Item* i) : state_(REFERENCED), item_(i), should_generate_(false) { } ItemNode::~ItemNode() { } bool ItemNode::SetShouldGenerate(const BuildSettings* build_settings, Err* err) { if (should_generate_) return true; should_generate_ = true; if (state_ == DEFINED) { if (!ScheduleDepsLoad(build_settings, err)) return false; } else if (state_ == RESOLVED) { // The item may have been resolved even if we didn't set the generate bit // if all of its deps were loaded some other way. In this case, we need // to run the closure which we skipped when it became resolved. if (!resolved_closure_.is_null()) resolved_closure_.Run(); } // Pass the generate bit to all deps. for (ItemNodeMap::iterator i = direct_dependencies_.begin(); i != direct_dependencies_.end(); ++i) { if (!i->first->SetShouldGenerate(build_settings, err)) return false; } return true; } bool ItemNode::AddDependency(const BuildSettings* build_settings, const LocationRange& specified_from_here, ItemNode* node, Err* err) { // Can't add more deps once it's been defined. DCHECK(state_ == REFERENCED); if (direct_dependencies_.find(node) != direct_dependencies_.end()) return true; // Already have this dep. direct_dependencies_[node] = specified_from_here; if (node->state() != RESOLVED) { // Wire up the pending resolution info. unresolved_dependencies_[node] = specified_from_here; node->waiting_on_resolution_[this] = specified_from_here; } if (should_generate_) { if (!node->SetShouldGenerate(build_settings, err)) return false; } return true; } void ItemNode::MarkDirectDependencyResolved(ItemNode* node) { DCHECK(unresolved_dependencies_.find(node) != unresolved_dependencies_.end()); unresolved_dependencies_.erase(node); } void ItemNode::SwapOutWaitingDependencySet(ItemNodeMap* out_map) { waiting_on_resolution_.swap(*out_map); DCHECK(waiting_on_resolution_.empty()); } bool ItemNode::SetDefined(const BuildSettings* build_settings, Err* err) { DCHECK(state_ == REFERENCED); state_ = DEFINED; if (should_generate_) return ScheduleDepsLoad(build_settings, err); return true; } void ItemNode::SetResolved() { DCHECK(state_ != RESOLVED); state_ = RESOLVED; if (should_generate_ && !resolved_closure_.is_null()) resolved_closure_.Run(); } bool ItemNode::ScheduleDepsLoad(const BuildSettings* build_settings, Err* err) { DCHECK(state_ == DEFINED); DCHECK(should_generate_); // Shouldn't be requesting deps for ungenerated // items. for (ItemNodeMap::const_iterator i = unresolved_dependencies_.begin(); i != unresolved_dependencies_.end(); ++i) { Label toolchain_label = i->first->item()->label().GetToolchainLabel(); SourceDir dir_to_load = i->first->item()->label().dir(); if (!build_settings->toolchain_manager().ScheduleInvocationLocked( i->second, toolchain_label, dir_to_load, err)) return false; } state_ = PENDING_DEPS; return true; }