Mark a phony target with no inputs as outputs-ready
authorPeter Collingbourne <peter@pcc.me.uk>
Mon, 5 Mar 2012 01:35:44 +0000 (01:35 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Mon, 5 Mar 2012 01:53:54 +0000 (01:53 +0000)
Even if such a target is dirty (i.e. the file does not exist), it
has nothing to do, which makes it safe to mark as outputs-ready.
Without this change, ninja will print no output when rebuilding the
target (or an order-only dependency thereof), instead of reporting
it has "no work to do".

src/build_test.cc
src/graph.cc

index ca74ab6..5b35513 100644 (file)
@@ -996,3 +996,29 @@ TEST_F(BuildTest, InterruptCleanup) {
   builder_.Cleanup();
   EXPECT_EQ(0, fs_.Stat("out2"));
 }
+
+TEST_F(BuildTest, PhonyWithNoInputs) {
+  ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build nonexistent: phony\n"
+"build out1: cat || nonexistent\n"
+"build out2: cat nonexistent\n"));
+  fs_.Create("out1", now_, "");
+  fs_.Create("out2", now_, "");
+
+  // out1 should be up to date even though its input is dirty, because its
+  // order-only dependency has nothing to do.
+  string err;
+  EXPECT_TRUE(builder_.AddTarget("out1", &err));
+  ASSERT_EQ("", err);
+  EXPECT_TRUE(builder_.AlreadyUpToDate());
+
+  // out2 should still be out of date though, because its input is dirty.
+  err.clear();
+  commands_ran_.clear();
+  state_.Reset();
+  EXPECT_TRUE(builder_.AddTarget("out2", &err));
+  ASSERT_EQ("", err);
+  EXPECT_TRUE(builder_.Build(&err));
+  EXPECT_EQ("", err);
+  ASSERT_EQ(1u, commands_ran_.size());
+}
index e2f966c..9d45ce1 100644 (file)
@@ -96,10 +96,10 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
       (*i)->MarkDirty();
   }
 
-  // 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)
+  // If we're dirty, our outputs are normally not ready.  (It's possible to be
+  // clean but still not be ready in the presence of order-only inputs.)
+  // But phony edges with no inputs have nothing to do, so are always ready.
+  if (dirty && !(is_phony() && inputs_.empty()))
     outputs_ready_ = false;
 
   return true;