summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/build.cc11
-rw-r--r--src/build.h9
-rw-r--r--src/build_test.cc24
-rw-r--r--src/ninja.cc17
4 files changed, 41 insertions, 20 deletions
diff --git a/src/build.cc b/src/build.cc
index 3b7d5b8..e0118ef 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -387,7 +387,7 @@ bool Builder::AddTarget(Node* node, string* err) {
return false;
}
if (!node->dirty_)
- return false; // Intentionally no error.
+ return true; // Nothing to do.
if (!plan_.AddTarget(node, err))
return false;
@@ -395,11 +395,12 @@ bool Builder::AddTarget(Node* node, string* err) {
return true;
}
+bool Builder::AlreadyUpToDate() const {
+ return !plan_.more_to_do();
+}
+
bool Builder::Build(string* err) {
- if (!plan_.more_to_do()) {
- *err = "no work to do";
- return true;
- }
+ assert(!AlreadyUpToDate());
status_->PlanHasTotalEdges(plan_.command_edge_count());
int pending_commands = 0;
diff --git a/src/build.h b/src/build.h
index 5969441..0f7303e 100644
--- a/src/build.h
+++ b/src/build.h
@@ -97,7 +97,16 @@ struct Builder {
Builder(State* state, const BuildConfig& config);
Node* AddTarget(const string& name, string* err);
+
+ /// Add a target to the build, scanning dependencies.
+ /// @return false on error.
bool AddTarget(Node* target, string* err);
+
+ /// Returns true if the build targets are already up to date.
+ bool AlreadyUpToDate() const;
+
+ /// Run the build. Returns false on error.
+ /// It is an error to call this function when AlreadyUpToDate() is true.
bool Build(string* err);
bool StartEdge(Edge* edge, string* err);
diff --git a/src/build_test.cc b/src/build_test.cc
index 282e4b7..db69628 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -278,9 +278,7 @@ Edge* BuildTest::WaitForCommand(bool* success, string* output) {
TEST_F(BuildTest, NoWork) {
string err;
- EXPECT_TRUE(builder_.Build(&err));
- EXPECT_EQ("no work to do", err);
- EXPECT_EQ(0u, commands_ran_.size());
+ EXPECT_TRUE(builder_.AlreadyUpToDate());
}
TEST_F(BuildTest, OneStep) {
@@ -375,10 +373,9 @@ TEST_F(BuildTest, Chain) {
err.clear();
commands_ran_.clear();
- EXPECT_FALSE(builder_.AddTarget("c5", &err));
+ EXPECT_TRUE(builder_.AddTarget("c5", &err));
ASSERT_EQ("", err);
- EXPECT_TRUE(builder_.Build(&err));
- ASSERT_EQ(0u, commands_ran_.size());
+ EXPECT_TRUE(builder_.AlreadyUpToDate());
GetNode("c4")->dirty_ = true;
GetNode("c5")->dirty_ = true;
@@ -386,6 +383,7 @@ TEST_F(BuildTest, Chain) {
commands_ran_.clear();
EXPECT_TRUE(builder_.AddTarget("c5", &err));
ASSERT_EQ("", err);
+ EXPECT_FALSE(builder_.AlreadyUpToDate());
EXPECT_TRUE(builder_.Build(&err));
ASSERT_EQ(2u, commands_ran_.size()); // 3->4, 4->5
}
@@ -523,10 +521,9 @@ TEST_F(BuildTest, OrderOnlyDeps) {
// order only dep dirty, no rebuild.
commands_ran_.clear();
GetNode("otherfile")->dirty_ = true;
- // We should fail to even add the depenency on foo.o, because
- // there's nothing to do.
- EXPECT_FALSE(builder_.AddTarget("foo.o", &err));
+ EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
EXPECT_EQ("", err);
+ EXPECT_TRUE(builder_.AlreadyUpToDate());
}
TEST_F(BuildTest, Phony) {
@@ -540,12 +537,17 @@ TEST_F(BuildTest, Phony) {
ASSERT_EQ("", err);
// Only one command to run, because phony runs no command.
+ EXPECT_FALSE(builder_.AlreadyUpToDate());
EXPECT_TRUE(builder_.Build(&err));
ASSERT_EQ("", err);
ASSERT_EQ(1u, commands_ran_.size());
- EXPECT_TRUE(builder_.Build(&err));
- ASSERT_NE("", err);
+ // XXX need a test that asserts we do nothing when we only
+ // have pending phony rules.
+ // fs_.Create("out", now_, "");
+ // EXPECT_TRUE(builder_.AddTarget("all", &err));
+ // ASSERT_EQ("", err);
+ // EXPECT_TRUE(builder_.AlreadyUpToDate());
}
TEST_F(BuildTest, Fail) {
diff --git a/src/ninja.cc b/src/ninja.cc
index cdaab3a..e892f9d 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -109,6 +109,8 @@ struct RealFileReader : public ManifestParser::FileReader {
}
};
+/// Rebuild the build manifest, if necessary.
+/// Returns true if the manifest was rebuilt.
bool RebuildManifest(State* state, const BuildConfig& config,
const char* input_file, string* err) {
string path = input_file;
@@ -121,6 +123,8 @@ bool RebuildManifest(State* state, const BuildConfig& config,
if (!manifest_builder.AddTarget(node, err))
return false;
+ if (manifest_builder.AlreadyUpToDate())
+ return false; // Not an error, but we didn't rebuild.
return manifest_builder.Build(err);
}
@@ -498,10 +502,15 @@ reload:
}
}
- bool success = builder.Build(&err);
- if (!err.empty()) {
- printf("build stopped: %s.\n", err.c_str());
+ if (builder.AlreadyUpToDate()) {
+ printf("ninja: no work to do.\n");
+ return 0;
}
- return success ? 0 : 1;
+ if (!builder.Build(&err)) {
+ printf("ninja: build stopped: %s.\n", err.c_str());
+ return 1;
+ }
+
+ return 0;
}