diff options
author | Evan Martin <martine@danga.com> | 2012-01-05 23:20:07 (GMT) |
---|---|---|
committer | Evan Martin <martine@danga.com> | 2012-01-05 23:20:07 (GMT) |
commit | c633f316d74375b49808a0e98511ff224d519746 (patch) | |
tree | 0d880c4ecaecadc5106ee68ad45906584668888a /src | |
parent | d5165bafdabbfba23d33a5e0ceb9e0e680384183 (diff) | |
download | Ninja-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.
Diffstat (limited to 'src')
-rw-r--r-- | src/build.cc | 15 | ||||
-rw-r--r-- | src/build_test.cc | 27 |
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()); +} |