Fix restat dirty check logic for edges with multiple outputs
authorChris Hopman <cjhopman@gmail.com>
Wed, 3 Jul 2013 21:26:25 +0000 (14:26 -0700)
committerNico Weber <nicolasweber@gmx.de>
Sat, 20 Jul 2013 19:11:18 +0000 (12:11 -0700)
In a normal dependency scan (see DependencyScan::RecomputeDirty) we mark
all outputs of an Edge as dirty if any of the outputs is dirty.  This is
the correct behavior because if any output is dirty, we will run the
command for that Edge and that can touch any of the outputs of the Edge
and so all the outputs should be marked dirty.

When updating the dirty state of Node's for a restat check, we were not
applying this logic, instead only those outputs that were actually
"dirty" were marked dirty.

Before this patch, restat edges with multiple outputs caused not all
dependent edges to run.

src/build.cc

index 2fbfdec..143aeb2 100644 (file)
@@ -422,23 +422,22 @@ void Plan::CleanNode(DependencyScan* scan, Node* node) {
       }
       string command = (*ei)->EvaluateCommand(true);
 
-      // Now, recompute the dirty state of each output.
-      bool all_outputs_clean = true;
+      // Now, this edge is dirty if any of the outputs are dirty.
+      bool dirty = false;
       for (vector<Node*>::iterator ni = (*ei)->outputs_.begin();
-           ni != (*ei)->outputs_.end(); ++ni) {
-        if (!(*ni)->dirty())
-          continue;
+           !dirty && ni != (*ei)->outputs_.end(); ++ni) {
+        dirty = scan->RecomputeOutputDirty(*ei, most_recent_input, 0,
+                                           command, *ni);
+      }
 
-        if (scan->RecomputeOutputDirty(*ei, most_recent_input, 0,
-                                       command, *ni)) {
-          all_outputs_clean = false;
-        } else {
+      // If the edge isn't dirty, clean the outputs and mark the edge as not
+      // wanted.
+      if (!dirty) {
+        for (vector<Node*>::iterator ni = (*ei)->outputs_.begin();
+             ni != (*ei)->outputs_.end(); ++ni) {
           CleanNode(scan, *ni);
         }
-      }
 
-      // If we cleaned all outputs, mark the edge as not wanted.
-      if (all_outputs_clean) {
         want_i->second = false;
         --wanted_edges_;
         if (!(*ei)->is_phony())