summaryrefslogtreecommitdiffstats
path: root/src/graph.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/graph.cc')
-rw-r--r--src/graph.cc85
1 files changed, 61 insertions, 24 deletions
diff --git a/src/graph.cc b/src/graph.cc
index 9c2f784..376b911 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -68,6 +68,31 @@ bool DependencyScan::RecomputeDirty(Node* node, vector<Node*>* stack,
edge->outputs_ready_ = true;
edge->deps_missing_ = false;
+ if (!edge->deps_loaded_) {
+ // This is our first encounter with this edge.
+ // If there is a pending dyndep file, visit it now:
+ // * If the dyndep file is ready then load it now to get any
+ // additional inputs and outputs for this and other edges.
+ // Once the dyndep file is loaded it will no longer be pending
+ // if any other edges encounter it, but they will already have
+ // been updated.
+ // * If the dyndep file is not ready then since is known to be an
+ // input to this edge, the edge will not be considered ready below.
+ // Later during the build the dyndep file will become ready and be
+ // loaded to update this edge before it can possibly be scheduled.
+ if (edge->dyndep_ && edge->dyndep_->dyndep_pending()) {
+ if (!RecomputeDirty(edge->dyndep_, stack, err))
+ return false;
+
+ if (!edge->dyndep_->in_edge() ||
+ edge->dyndep_->in_edge()->outputs_ready()) {
+ // The dyndep file is ready, so load it now.
+ if (!LoadDyndeps(edge->dyndep_, err))
+ return false;
+ }
+ }
+ }
+
// Load output mtimes so we can compare them to the most recent input below.
for (vector<Node*>::iterator o = edge->outputs_.begin();
o != edge->outputs_.end(); ++o) {
@@ -75,12 +100,16 @@ bool DependencyScan::RecomputeDirty(Node* node, vector<Node*>* stack,
return false;
}
- if (!dep_loader_.LoadDeps(edge, err)) {
- if (!err->empty())
- return false;
- // Failed to load dependency info: rebuild to regenerate it.
- // LoadDeps() did EXPLAIN() already, no need to do it here.
- dirty = edge->deps_missing_ = true;
+ if (!edge->deps_loaded_) {
+ // This is our first encounter with this edge. Load discovered deps.
+ edge->deps_loaded_ = true;
+ if (!dep_loader_.LoadDeps(edge, err)) {
+ if (!err->empty())
+ return false;
+ // Failed to load dependency info: rebuild to regenerate it.
+ // LoadDeps() did EXPLAIN() already, no need to do it here.
+ dirty = edge->deps_missing_ = true;
+ }
}
// Visit all inputs; we're dirty if any of the inputs are dirty.
@@ -272,6 +301,15 @@ bool DependencyScan::RecomputeOutputDirty(Edge* edge,
return false;
}
+bool DependencyScan::LoadDyndeps(Node* node, string* err) const {
+ return dyndep_loader_.LoadDyndeps(node, err);
+}
+
+bool DependencyScan::LoadDyndeps(Node* node, DyndepFile* ddf,
+ string* err) const {
+ return dyndep_loader_.LoadDyndeps(node, ddf, err);
+}
+
bool Edge::AllInputsReady() const {
for (vector<Node*>::const_iterator i = inputs_.begin();
i != inputs_.end(); ++i) {
@@ -285,19 +323,17 @@ bool Edge::AllInputsReady() const {
struct EdgeEnv : public Env {
enum EscapeKind { kShellEscape, kDoNotEscape };
- EdgeEnv(Edge* edge, EscapeKind escape)
+ EdgeEnv(const Edge* const edge, const EscapeKind escape)
: edge_(edge), escape_in_out_(escape), recursive_(false) {}
virtual string LookupVariable(const string& var);
/// Given a span of Nodes, construct a list of paths suitable for a command
/// line.
- string MakePathList(vector<Node*>::iterator begin,
- vector<Node*>::iterator end,
- char sep);
+ std::string MakePathList(const Node* const* span, size_t size, char sep) const;
private:
vector<string> lookups_;
- Edge* edge_;
+ const Edge* const edge_;
EscapeKind escape_in_out_;
bool recursive_;
};
@@ -306,14 +342,11 @@ string EdgeEnv::LookupVariable(const string& var) {
if (var == "in" || var == "in_newline") {
int explicit_deps_count = edge_->inputs_.size() - edge_->implicit_deps_ -
edge_->order_only_deps_;
- return MakePathList(edge_->inputs_.begin(),
- edge_->inputs_.begin() + explicit_deps_count,
+ return MakePathList(&edge_->inputs_[0], explicit_deps_count,
var == "in" ? ' ' : '\n');
} else if (var == "out") {
int explicit_outs_count = edge_->outputs_.size() - edge_->implicit_outs_;
- return MakePathList(edge_->outputs_.begin(),
- edge_->outputs_.begin() + explicit_outs_count,
- ' ');
+ return MakePathList(&edge_->outputs_[0], explicit_outs_count, ' ');
}
if (recursive_) {
@@ -338,11 +371,10 @@ string EdgeEnv::LookupVariable(const string& var) {
return edge_->env_->LookupWithFallback(var, eval, this);
}
-string EdgeEnv::MakePathList(vector<Node*>::iterator begin,
- vector<Node*>::iterator end,
- char sep) {
+std::string EdgeEnv::MakePathList(const Node* const* const span,
+ const size_t size, const char sep) const {
string result;
- for (vector<Node*>::iterator i = begin; i != end; ++i) {
+ for (const Node* const* i = span; i != span + size; ++i) {
if (!result.empty())
result.push_back(sep);
const string& path = (*i)->PathDecanonicalized();
@@ -359,7 +391,7 @@ string EdgeEnv::MakePathList(vector<Node*>::iterator begin,
return result;
}
-string Edge::EvaluateCommand(bool incl_rsp_file) {
+std::string Edge::EvaluateCommand(const bool incl_rsp_file) const {
string command = GetBinding("command");
if (incl_rsp_file) {
string rspfile_content = GetBinding("rspfile_content");
@@ -369,7 +401,7 @@ string Edge::EvaluateCommand(bool incl_rsp_file) {
return command;
}
-string Edge::GetBinding(const string& key) {
+std::string Edge::GetBinding(const std::string& key) const {
EdgeEnv env(this, EdgeEnv::kShellEscape);
return env.LookupVariable(key);
}
@@ -383,7 +415,12 @@ string Edge::GetUnescapedDepfile() {
return env.LookupVariable("depfile");
}
-string Edge::GetUnescapedRspfile() {
+string Edge::GetUnescapedDyndep() {
+ EdgeEnv env(this, EdgeEnv::kDoNotEscape);
+ return env.LookupVariable("dyndep");
+}
+
+std::string Edge::GetUnescapedRspfile() const {
EdgeEnv env(this, EdgeEnv::kDoNotEscape);
return env.LookupVariable("rspfile");
}
@@ -541,7 +578,7 @@ bool ImplicitDepLoader::LoadDepFile(Edge* edge, const string& path,
bool ImplicitDepLoader::LoadDepsFromLog(Edge* edge, string* err) {
// NOTE: deps are only supported for single-target edges.
Node* output = edge->outputs_[0];
- DepsLog::Deps* deps = deps_log_->GetDeps(output);
+ DepsLog::Deps* deps = deps_log_ ? deps_log_->GetDeps(output) : NULL;
if (!deps) {
EXPLAIN("deps for '%s' are missing", output->path().c_str());
return false;