summaryrefslogtreecommitdiffstats
path: root/src/graph.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/graph.cc')
-rw-r--r--src/graph.cc17
1 files changed, 14 insertions, 3 deletions
diff --git a/src/graph.cc b/src/graph.cc
index 57f790c..44eca3c 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -62,6 +62,19 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
edge->outputs_ready_ = true;
edge->deps_missing_ = false;
+ // RecomputeDirty() recursively walks the graph following the input nodes
+ // of |edge| and the in_edges of these nodes. It uses the stat state of each
+ // node to mark nodes as visited and doesn't traverse across nodes that have
+ // been visited already. To make sure that every edge is visited only once
+ // (important because an edge's deps are loaded every time it's visited), mark
+ // all outputs of |edge| visited as a first step. This ensures that edges
+ // with multiple inputs and outputs are visited only once, even in cyclic
+ // graphs.
+ for (vector<Node*>::iterator o = edge->outputs_.begin();
+ o != edge->outputs_.end(); ++o) {
+ (*o)->StatIfNecessary(disk_interface_);
+ }
+
if (!dep_loader_.LoadDeps(edge, err)) {
if (!err->empty())
return false;
@@ -110,11 +123,9 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
if (!dirty)
dirty = RecomputeOutputsDirty(edge, most_recent_input);
- // Finally, visit each output to mark off that we've visited it, and update
- // their dirty state if necessary.
+ // Finally, visit each output and update their dirty state if necessary.
for (vector<Node*>::iterator o = edge->outputs_.begin();
o != edge->outputs_.end(); ++o) {
- (*o)->StatIfNecessary(disk_interface_);
if (dirty)
(*o)->MarkDirty();
}