summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorScott Graham <scottmg@chromium.org>2012-08-15 04:09:19 (GMT)
committerEvan Martin <martine@danga.com>2012-08-15 04:09:19 (GMT)
commitb56fe8082bfd59205efb55f6b1e7862045e005f2 (patch)
treec10805e66fe986d7ab3a0f4ff5f8d0a5fbaadd7d /src
parentac04abe2f9c87afe4e4d43ac63e5af2dd10376fb (diff)
downloadNinja-b56fe8082bfd59205efb55f6b1e7862045e005f2.zip
Ninja-b56fe8082bfd59205efb55f6b1e7862045e005f2.tar.gz
Ninja-b56fe8082bfd59205efb55f6b1e7862045e005f2.tar.bz2
if a file is missing in the log, count it as dirty
This could cause overbuilding (if the log is missing an entry and the right file is already in place) but is otherwise necessary for correctness (if a file is already in place but we don't have a log entry for it).
Diffstat (limited to 'src')
-rw-r--r--src/build_test.cc56
-rw-r--r--src/graph.cc13
2 files changed, 63 insertions, 6 deletions
diff --git a/src/build_test.cc b/src/build_test.cc
index 574ffb4..d4673ae 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -723,6 +723,31 @@ struct BuildWithLogTest : public BuildTest {
BuildLog build_log_;
};
+TEST_F(BuildWithLogTest, NotInLogButOnDisk) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cc\n"
+" command = cc\n"
+"build out1: cc in\n"));
+
+ // Create input/output that would be considered up to date when
+ // not considering the command line hash.
+ fs_.Create("in", now_, "");
+ fs_.Create("out1", now_, "");
+ string err;
+
+ // Because it's not in the log, it should not be up-to-date until
+ // we build again.
+ EXPECT_TRUE(builder_.AddTarget("out1", &err));
+ EXPECT_FALSE(builder_.AlreadyUpToDate());
+
+ commands_ran_.clear();
+ state_.Reset();
+
+ EXPECT_TRUE(builder_.AddTarget("out1", &err));
+ EXPECT_TRUE(builder_.Build(&err));
+ EXPECT_TRUE(builder_.AlreadyUpToDate());
+}
+
TEST_F(BuildWithLogTest, RestatTest) {
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"rule true\n"
@@ -743,9 +768,22 @@ TEST_F(BuildWithLogTest, RestatTest) {
fs_.Create("in", now_, "");
+ // Do a pre-build so that there's commands in the log for the outputs,
+ // otherwise, the lack of an entry in the build log will cause out3 to rebuild
+ // regardless of restat.
+ string err;
+ EXPECT_TRUE(builder_.AddTarget("out3", &err));
+ ASSERT_EQ("", err);
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ("", err);
+ commands_ran_.clear();
+ state_.Reset();
+
+ now_++;
+
+ fs_.Create("in", now_, "");
// "cc" touches out1, so we should build out2. But because "true" does not
// touch out2, we should cancel the build of out3.
- string err;
EXPECT_TRUE(builder_.AddTarget("out3", &err));
ASSERT_EQ("", err);
EXPECT_TRUE(builder_.Build(&err));
@@ -790,10 +828,24 @@ TEST_F(BuildWithLogTest, RestatMissingFile) {
fs_.Create("in", now_, "");
fs_.Create("out2", now_, "");
+ // Do a pre-build so that there's commands in the log for the outputs,
+ // otherwise, the lack of an entry in the build log will cause out2 to rebuild
+ // regardless of restat.
+ string err;
+ EXPECT_TRUE(builder_.AddTarget("out2", &err));
+ ASSERT_EQ("", err);
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ("", err);
+ commands_ran_.clear();
+ state_.Reset();
+
+ now_++;
+ 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));
diff --git a/src/graph.cc b/src/graph.cc
index 18adeee..9654c1a 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -158,10 +158,15 @@ bool Edge::RecomputeOutputDirty(BuildLog* build_log,
// May also be dirty due to the command changing since the last build.
// But if this is a generator rule, the command changing does not make us
// dirty.
- if (!rule_->generator() && build_log &&
- (entry || (entry = build_log->LookupByOutput(output->path())))) {
- if (BuildLog::LogEntry::HashCommand(command) != entry->command_hash) {
- EXPLAIN("command line changed for %s", output->path().c_str());
+ if (!rule_->generator() && build_log) {
+ if (entry || (entry = build_log->LookupByOutput(output->path()))) {
+ if (BuildLog::LogEntry::HashCommand(command) != entry->command_hash) {
+ EXPLAIN("command line changed for %s", output->path().c_str());
+ return true;
+ }
+ }
+ if (!entry) {
+ EXPLAIN("command line not found in log for %s", output->path().c_str());
return true;
}
}