safer build: consider target dirty if depfile is missing
authorMaxim Kalaev <maximk@il.ibm.com>
Wed, 29 Aug 2012 20:25:44 +0000 (22:25 +0200)
committerMaxim Kalaev <maximk@il.ibm.com>
Thu, 30 Aug 2012 17:53:51 +0000 (19:53 +0200)
src/graph.cc
src/graph_test.cc

index 9654c1a..3567bfa 100644 (file)
@@ -38,8 +38,13 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
   outputs_ready_ = true;
 
   if (!rule_->depfile().empty()) {
-    if (!LoadDepFile(state, disk_interface, err))
-      return false;
+    if (!LoadDepFile(state, disk_interface, err)) {
+      if (!err->empty())
+        return false;
+      EXPLAIN("Edge targets are dirty because depfile '%s' is missing",
+              EvaluateDepFile().c_str());
+      dirty = true;
+    }
   }
 
   // Visit all inputs; we're dirty if any of the inputs are dirty.
@@ -274,8 +279,9 @@ bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface,
   string content = disk_interface->ReadFile(path, err);
   if (!err->empty())
     return false;
+  // On a missing depfile: return false and empty *err.
   if (content.empty())
-    return true;
+    return false;
 
   DepfileParser depfile;
   string depfile_err;
index 38ff28a..4b41f8a 100644 (file)
@@ -159,3 +159,28 @@ TEST_F(GraphTest, DepfileWithCanonicalizablePath) {
 
   EXPECT_FALSE(GetNode("out.o")->dirty());
 }
+
+// Regression test for https://github.com/martine/ninja/issues/404
+TEST_F(GraphTest, DepfileRemoved) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule catdep\n"
+"  depfile = $out.d\n"
+"  command = cat $in > $out\n"
+"build ./out.o: catdep ./foo.cc\n"));
+  fs_.Create("foo.h", 1, "");
+  fs_.Create("foo.cc", 1, "");
+  fs_.Create("out.o.d", 2, "out.o: foo.h\n");
+  fs_.Create("out.o", 2, "");
+
+  Edge* edge = GetNode("out.o")->in_edge();
+  string err;
+  EXPECT_TRUE(edge->RecomputeDirty(&state_, &fs_, &err));
+  ASSERT_EQ("", err);
+  EXPECT_FALSE(GetNode("out.o")->dirty());
+
+  state_.Reset();
+  fs_.RemoveFile("out.o.d");
+  EXPECT_TRUE(edge->RecomputeDirty(&state_, &fs_, &err));
+  ASSERT_EQ("", err);
+  EXPECT_TRUE(GetNode("out.o")->dirty());
+}