summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/manual.asciidoc6
-rw-r--r--src/build_test.cc30
-rw-r--r--src/graph.cc5
-rw-r--r--src/stat_cache.cc5
-rw-r--r--src/stat_cache.h2
5 files changed, 40 insertions, 8 deletions
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index 9506f0c..ed44bd2 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -277,6 +277,12 @@ nothing, but phony rules are handled specially in that they aren't
printed when run, logged (see below), nor do they contribute to the
command count printed as part of the build process.
+`phony' can also be used to create dummy targets for files which
+may not exist at build time. If a phony build statement is written
+without any dependencies, the target will be considered out of date if
+it does not exist. Without a phony build statement, Ninja will report
+an error if the file does not exist and is required by the build.
+
Default target statements
~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/build_test.cc b/src/build_test.cc
index c8d338b..84359a3 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -250,8 +250,7 @@ bool BuildTest::StartCommand(Edge* edge) {
edge->rule_->name_ == "touch") {
for (vector<Node*>::iterator out = edge->outputs_.begin();
out != edge->outputs_.end(); ++out) {
- (*out)->file_->mtime_ = now_;
- (*out)->dirty_ = false;
+ fs_.Create((*out)->file_->path_, now_, "");
}
} else if (edge->rule_->name_ == "fail") {
// Don't do anything.
@@ -373,14 +372,17 @@ TEST_F(BuildTest, Chain) {
err.clear();
commands_ran_.clear();
+ state_.stat_cache_.Invalidate();
EXPECT_TRUE(builder_.AddTarget("c5", &err));
ASSERT_EQ("", err);
EXPECT_TRUE(builder_.AlreadyUpToDate());
- GetNode("c4")->dirty_ = true;
- GetNode("c5")->dirty_ = true;
+ now_++;
+
+ fs_.Create("c3", now_, "");
err.clear();
commands_ran_.clear();
+ state_.stat_cache_.Invalidate();
EXPECT_TRUE(builder_.AddTarget("c5", &err));
ASSERT_EQ("", err);
EXPECT_FALSE(builder_.AlreadyUpToDate());
@@ -510,20 +512,36 @@ TEST_F(BuildTest, OrderOnlyDeps) {
ASSERT_EQ("", err);
ASSERT_EQ(1u, commands_ran_.size());
+ now_++;
+
// implicit dep dirty, expect a rebuild.
+ fs_.Create("blah.h", now_, "");
+ fs_.Create("bar.h", now_, "");
commands_ran_.clear();
- GetNode("blah.h")->dirty_ = true;
+ state_.stat_cache_.Invalidate();
EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
EXPECT_TRUE(builder_.Build(&err));
ASSERT_EQ("", err);
ASSERT_EQ(1u, commands_ran_.size());
+ now_++;
+
// order only dep dirty, no rebuild.
+ fs_.Create("otherfile", now_, "");
commands_ran_.clear();
- GetNode("otherfile")->dirty_ = true;
+ state_.stat_cache_.Invalidate();
EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
EXPECT_EQ("", err);
EXPECT_TRUE(builder_.AlreadyUpToDate());
+
+ // implicit dep missing, expect rebuild.
+ fs_.RemoveFile("bar.h");
+ commands_ran_.clear();
+ state_.stat_cache_.Invalidate();
+ EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ("", err);
+ ASSERT_EQ(1u, commands_ran_.size());
}
TEST_F(BuildTest, Phony) {
diff --git a/src/graph.cc b/src/graph.cc
index 643d74f..16299c0 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -77,9 +77,12 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
if (is_phony()) {
// Phony edges don't write any output.
- // They're only dirty if an input is dirty.
+ // They're only dirty if an input is dirty, or if there are no inputs
+ // and we're missing the output.
if (dirty)
(*i)->dirty_ = true;
+ else if (inputs_.empty() && !(*i)->file_->exists())
+ (*i)->dirty_ = true;
continue;
}
diff --git a/src/stat_cache.cc b/src/stat_cache.cc
index 75248be..0b717b4 100644
--- a/src/stat_cache.cc
+++ b/src/stat_cache.cc
@@ -36,3 +36,8 @@ void StatCache::Dump() {
: "unknown");
}
}
+
+void StatCache::Invalidate() {
+ for (Paths::iterator i = paths_.begin(); i != paths_.end(); ++i)
+ i->second->mtime_ = -1;
+}
diff --git a/src/stat_cache.h b/src/stat_cache.h
index 9cb3eff..f071e59 100644
--- a/src/stat_cache.h
+++ b/src/stat_cache.h
@@ -29,7 +29,7 @@ struct StatCache {
/// Dump the mapping to stdout (useful for debugging).
void Dump();
- void Reload();
+ void Invalidate();
typedef ExternalStringHashMap<FileStat*>::Type Paths;
Paths paths_;