blob: f10bada584dc26d8aad38c5e99910b455099c0a0 [file] [log] [blame]
// 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 <algorithm>
#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;
}