summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2012-01-05 23:20:07 (GMT)
committerEvan Martin <martine@danga.com>2012-01-05 23:20:07 (GMT)
commitc633f316d74375b49808a0e98511ff224d519746 (patch)
tree0d880c4ecaecadc5106ee68ad45906584668888a
parentd5165bafdabbfba23d33a5e0ceb9e0e680384183 (diff)
downloadNinja-c633f316d74375b49808a0e98511ff224d519746.zip
Ninja-c633f316d74375b49808a0e98511ff224d519746.tar.gz
Ninja-c633f316d74375b49808a0e98511ff224d519746.tar.bz2
adjust restat behavior around missing outputs
If a restat rule claims to write an output but doesn't, consider it "no change" (in the restat sense) if the output didn't exist beforehand. I.e. if the output didn't exist before and the output doesn't exist after, we don't need to run dependent rules.
-rw-r--r--src/build.cc15
-rw-r--r--src/build_test.cc27
2 files changed, 34 insertions, 8 deletions
diff --git a/src/build.cc b/src/build.cc
index cd1618c..ebf63b2 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -577,14 +577,13 @@ void Builder::FinishEdge(Edge* edge, bool success, const string& output) {
for (vector<Node*>::iterator i = edge->outputs_.begin();
i != edge->outputs_.end(); ++i) {
- if ((*i)->exists()) {
- TimeStamp new_mtime = disk_interface_->Stat((*i)->path());
- if ((*i)->mtime() == new_mtime) {
- // The rule command did not change the output. Propagate the clean
- // state through the build graph.
- plan_.CleanNode(log_, *i);
- node_cleaned = true;
- }
+ TimeStamp new_mtime = disk_interface_->Stat((*i)->path());
+ if ((*i)->mtime() == new_mtime) {
+ // The rule command did not change the output. Propagate the clean
+ // state through the build graph.
+ // Note that this also applies to nonexistent outputs (mtime == 0).
+ plan_.CleanNode(log_, *i);
+ node_cleaned = true;
}
}
diff --git a/src/build_test.cc b/src/build_test.cc
index 40d116f..7f977a6 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -745,3 +745,30 @@ TEST_F(BuildWithLogTest, RestatTest) {
EXPECT_TRUE(builder_.Build(&err));
ASSERT_EQ(2u, commands_ran_.size());
}
+
+TEST_F(BuildWithLogTest, RestatMissingFile) {
+ // If a restat rule doesn't create its output, and the output didn't
+ // exist before the rule was run, consider that behavior equivalent
+ // to a rule that doesn't modify its existent output file.
+
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule true\n"
+" command = true\n"
+" restat = 1\n"
+"rule cc\n"
+" command = cc\n"
+"build out1: true in\n"
+"build out2: cc out1\n"));
+
+ fs_.Create("in", now_, "");
+ fs_.Create("out2", now_, "");
+
+ // Run a build, expect only the first command to run.
+ // It doesn't touch its output (due to being the "true" command), so
+ // we shouldn't run the dependent build.
+ string err;
+ EXPECT_TRUE(builder_.AddTarget("out2", &err));
+ ASSERT_EQ("", err);
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ(1u, commands_ran_.size());
+}