multi-level build works
authorEvan Martin <martine@danga.com>
Mon, 18 Oct 2010 02:13:07 +0000 (19:13 -0700)
committerEvan Martin <martine@danga.com>
Mon, 18 Oct 2010 02:13:18 +0000 (19:13 -0700)
ninja.h
ninja_test.cc

diff --git a/ninja.h b/ninja.h
index a417572a075427bec5e7e9ee8c74e0c29a8e3df2..b98ba4fa188ffac6bd682e6a0479ee9b64e1d429 100644 (file)
--- a/ninja.h
+++ b/ninja.h
@@ -160,6 +160,7 @@ struct StatCache {
   typedef map<string, FileStat*> Paths;
   Paths paths_;
   FileStat* GetFile(const string& path);
+  void Dump();
 };
 
 FileStat* StatCache::GetFile(const string& path) {
@@ -171,6 +172,15 @@ FileStat* StatCache::GetFile(const string& path) {
   return file;
 }
 
+#include <stdio.h>
+
+void StatCache::Dump() {
+  for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i) {
+    printf("%s %s\n", i->second->path_.c_str(),
+           i->second->node_->dirty_ ? "dirty" : "clean");
+  }
+}
+
 struct State {
   StatCache stat_cache_;
   map<string, Rule*> rules_;
@@ -228,6 +238,8 @@ struct Plan {
   bool AddTarget(Node* node);
 
   Edge* FindWork();
+  void EdgeFinished(Edge* edge);
+  void NodeFinished(Node* node);
 
   State* state_;
   set<Node*> want_;
@@ -250,7 +262,8 @@ bool Plan::AddTarget(Node* node) {
   want_.insert(node);
 
   bool awaiting_inputs = false;
-  for (vector<Node*>::iterator i = edge->inputs_.begin(); i != edge->inputs_.end(); ++i) {
+  for (vector<Node*>::iterator i = edge->inputs_.begin();
+       i != edge->inputs_.end(); ++i) {
     if (AddTarget(*i))
       awaiting_inputs = true;
   }
@@ -269,6 +282,46 @@ Edge* Plan::FindWork() {
   return edge;
 }
 
+void Plan::EdgeFinished(Edge* edge) {
+  // Check off any nodes we were waiting for with this edge.
+  for (vector<Node*>::iterator i = edge->outputs_.begin();
+       i != edge->outputs_.end(); ++i) {
+    set<Node*>::iterator j = want_.find(*i);
+    if (j != want_.end()) {
+      NodeFinished(*j);
+      want_.erase(j);
+    }
+  }
+}
+
+void Plan::NodeFinished(Node* node) {
+  // See if we we want any edges from this node.
+  for (vector<Edge*>::iterator i = node->out_edges_.begin();
+       i != node->out_edges_.end(); ++i) {
+    // See if we want any outputs from this edge.
+    for (vector<Node*>::iterator j = (*i)->outputs_.begin();
+         j != (*i)->outputs_.end(); ++j) {
+      if (want_.find(*j) != want_.end()) {
+        // See if the edge is ready.
+        // XXX just track dirty counts.
+        // XXX may double-enqueue edge.
+        bool ready = true;
+        for (vector<Node*>::iterator k = (*i)->inputs_.begin();
+             k != (*i)->inputs_.end(); ++k) {
+          if ((*k)->dirty()) {
+            ready = false;
+            break;
+          }
+        }
+        if (ready)
+          ready_.push(*i);
+        break;
+      }
+    }
+  }
+}
+
+
 #include "manifest_parser.h"
 
 struct Shell {
@@ -306,8 +359,19 @@ bool Builder::Build(Shell* shell, string* err) {
       err->assign("command '" + command + "' failed.");
       return false;
     }
-    // XXX tell plan about the files we've updated, so we have more
-    // work to do
+    for (vector<Node*>::iterator i = edge->outputs_.begin();
+         i != edge->outputs_.end(); ++i) {
+      // XXX check that the output actually changed
+      // XXX just notify node and have it propagate?
+      (*i)->dirty_ = false;
+    }
+    plan_.EdgeFinished(edge);
   } while ((edge = plan_.FindWork()) != NULL);
+
+  if (!plan_.want_.empty()) {
+    *err = "ran out of work";
+    return false;
+  }
+
   return true;
 }
index a759b1846e917301655ecc428d3768c8cbceaed9..c4c359727c075861a1bb8ebfe11aabb109f38b82 100644 (file)
@@ -164,15 +164,15 @@ TEST_F(BuildTest, OneStep2) {
   EXPECT_EQ("cat in1 > cat1", commands_ran_[0]);
 }
 
-/*
 TEST_F(BuildTest, TwoStep) {
-  Touch("cat12");
+  Touch("in1");
   builder_.AddTarget("cat12");
   string err;
   EXPECT_TRUE(builder_.Build(this, &err));
   EXPECT_EQ("", err);
 
-  ASSERT_EQ(1, commands_ran_.size());
+  ASSERT_EQ(3, commands_ran_.size());
   EXPECT_EQ("cat in1 > cat1", commands_ran_[0]);
+  EXPECT_EQ("cat in1 in2 > cat2", commands_ran_[1]);
+  EXPECT_EQ("cat cat1 cat2 > cat12", commands_ran_[2]);
 }
-*/