summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build_test.cc26
-rw-r--r--src/disk_interface.cc2
-rw-r--r--src/disk_interface_test.cc26
-rw-r--r--src/graph.cc8
-rw-r--r--src/ninja.cc12
5 files changed, 53 insertions, 21 deletions
diff --git a/src/build_test.cc b/src/build_test.cc
index ca74ab6..5b35513 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -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());
+}
diff --git a/src/disk_interface.cc b/src/disk_interface.cc
index 96a1e59..b1a1746 100644
--- a/src/disk_interface.cc
+++ b/src/disk_interface.cc
@@ -94,7 +94,7 @@ TimeStamp RealDiskInterface::Stat(const string& path) {
#else
struct stat st;
if (stat(path.c_str(), &st) < 0) {
- if (errno == ENOENT)
+ if (errno == ENOENT || errno == ENOTDIR)
return 0;
Error("stat(%s): %s", path.c_str(), strerror(errno));
return -1;
diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc
index 052a94b..67e2a04 100644
--- a/src/disk_interface_test.cc
+++ b/src/disk_interface_test.cc
@@ -36,6 +36,13 @@ class DiskInterfaceTest : public testing::Test {
temp_dir_.Cleanup();
}
+ bool Touch(const char* path) {
+ FILE *f = fopen(path, "w");
+ if (!f)
+ return false;
+ return fclose(f) == 0;
+ }
+
ScopedTempDir temp_dir_;
RealDiskInterface disk_;
};
@@ -46,6 +53,11 @@ TEST_F(DiskInterfaceTest, StatMissingFile) {
// On Windows, the errno for a file in a nonexistent directory
// is different.
EXPECT_EQ(0, disk_.Stat("nosuchdir/nosuchfile"));
+
+ // On POSIX systems, the errno is different if a component of the
+ // path prefix is not a directory.
+ ASSERT_TRUE(Touch("notadir"));
+ EXPECT_EQ(0, disk_.Stat("notadir/nosuchfile"));
}
TEST_F(DiskInterfaceTest, StatBadPath) {
@@ -56,11 +68,7 @@ TEST_F(DiskInterfaceTest, StatBadPath) {
}
TEST_F(DiskInterfaceTest, StatExistingFile) {
-#ifdef _WIN32
- ASSERT_EQ(0, system("cmd.exe /c echo hi > file"));
-#else
- ASSERT_EQ(0, system("touch file"));
-#endif
+ ASSERT_TRUE(Touch("file"));
EXPECT_GT(disk_.Stat("file"), 1);
}
@@ -86,13 +94,7 @@ TEST_F(DiskInterfaceTest, MakeDirs) {
TEST_F(DiskInterfaceTest, RemoveFile) {
const char* kFileName = "file-to-remove";
-#ifdef _WIN32
- string cmd = "cmd /c echo hi > ";
-#else
- string cmd = "touch ";
-#endif
- cmd += kFileName;
- ASSERT_EQ(0, system(cmd.c_str()));
+ ASSERT_TRUE(Touch(kFileName));
EXPECT_EQ(0, disk_.RemoveFile(kFileName));
EXPECT_EQ(1, disk_.RemoveFile(kFileName));
EXPECT_EQ(1, disk_.RemoveFile("does not exist"));
diff --git a/src/graph.cc b/src/graph.cc
index e2f966c..9d45ce1 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -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;
diff --git a/src/ninja.cc b/src/ninja.cc
index 0b3ffe5..04cd771 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -195,9 +195,13 @@ bool CollectTargetsFromArgs(State* state, int argc, char* argv[],
} else {
*err = "unknown target '" + path + "'";
- Node* suggestion = state->SpellcheckNode(path);
- if (suggestion) {
- *err += ", did you mean '" + suggestion->path() + "'?";
+ if (path == "clean") {
+ *err += ", did you mean 'ninja -t clean'?";
+ } else {
+ Node* suggestion = state->SpellcheckNode(path);
+ if (suggestion) {
+ *err += ", did you mean '" + suggestion->path() + "'?";
+ }
}
return false;
}
@@ -490,7 +494,7 @@ void ToolUrtle() {
"\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?"
"21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2"
"?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P"
-"\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n19$P2\",;23!6;17!;2 \"\n";
+"\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n";
int count = 0;
for (const char* p = urtle; *p; p++) {
if ('0' <= *p && *p <= '9') {