summaryrefslogtreecommitdiffstats
path: root/src/graph.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2011-12-04 21:07:11 (GMT)
committerEvan Martin <martine@danga.com>2011-12-04 21:07:11 (GMT)
commitf39ebbfa26105a8e0ae7a7cad0246d009b0d29d0 (patch)
tree4041e161232be7d9c6665363e8da40d1f59291af /src/graph.cc
parentd412c2cfec1f8cd4d6a94a895773fb7c562c839c (diff)
downloadNinja-f39ebbfa26105a8e0ae7a7cad0246d009b0d29d0.zip
Ninja-f39ebbfa26105a8e0ae7a7cad0246d009b0d29d0.tar.gz
Ninja-f39ebbfa26105a8e0ae7a7cad0246d009b0d29d0.tar.bz2
when an edge is dirty, mark all outputs dirty
The logic before was like: for each output: if edge_dirty or output.dirty: output.dirty = true edge_dirty = true This was wrong in the case where the second output would case the edge to be dirty; we needed to go back and mark the first output dirty as well. Fixed by taking two passes: one to compute the dirty state, then a latter sweep to mark all outputs. Fixes issue 148.
Diffstat (limited to 'src/graph.cc')
-rw-r--r--src/graph.cc34
1 files changed, 25 insertions, 9 deletions
diff --git a/src/graph.cc b/src/graph.cc
index 341cfd5..90791f9 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -39,6 +39,7 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
outputs_ready_ = true;
+ // Visit all inputs; we're dirty if any of the inputs are dirty.
time_t most_recent_input = 1;
for (vector<Node*>::iterator i = inputs_.begin(); i != inputs_.end(); ++i) {
if ((*i)->file_->StatIfNecessary(disk_interface)) {
@@ -68,21 +69,36 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
}
}
- BuildLog* build_log = state ? state->build_log_ : 0;
- string command = EvaluateCommand();
+ // We may also be dirty due to output state: missing outputs, out of
+ // date outputs, etc. Visit all outputs and determine whether they're dirty.
+ if (!dirty) {
+ BuildLog* build_log = state ? state->build_log_ : 0;
+ string command = EvaluateCommand();
+
+ for (vector<Node*>::iterator i = outputs_.begin();
+ i != outputs_.end(); ++i) {
+ (*i)->file_->StatIfNecessary(disk_interface);
+ if (RecomputeOutputDirty(build_log, most_recent_input, command, *i)) {
+ dirty = true;
+ break;
+ }
+ }
+ }
- assert(!outputs_.empty());
+ // Finally, visit each output to mark off that we've visited it, and update
+ // their dirty state if necessary.
for (vector<Node*>::iterator i = outputs_.begin(); i != outputs_.end(); ++i) {
- // We may have other outputs that our input-recursive traversal hasn't hit
- // yet (or never will). Stat them if we haven't already to mark that we've
- // visited their dependents.
(*i)->file_->StatIfNecessary(disk_interface);
- if (dirty || RecomputeOutputDirty(build_log, most_recent_input, command, *i)) {
+ if (dirty)
(*i)->dirty_ = true;
- outputs_ready_ = false;
- }
}
+ // If we're dirty, our outputs are not ready. (It's possible to be
+ // clean but still have not be ready in the presence of order-only
+ // inputs.)
+ if (dirty)
+ outputs_ready_ = false;
+
return true;
}