summaryrefslogtreecommitdiffstats
path: root/src/build_test.cc
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2011-09-18 02:28:44 (GMT)
committerPeter Collingbourne <peter@pcc.me.uk>2011-10-24 00:16:24 (GMT)
commit6fc220b8b98d0a89204f144557d935feb775aeca (patch)
treef61cf2a7b574f74cf1e4a7fd0d73003f8c3d4dd2 /src/build_test.cc
parent5ff5891f5bed923b983c0f5a23c16d988d55f30e (diff)
downloadNinja-6fc220b8b98d0a89204f144557d935feb775aeca.zip
Ninja-6fc220b8b98d0a89204f144557d935feb775aeca.tar.gz
Ninja-6fc220b8b98d0a89204f144557d935feb775aeca.tar.bz2
Implement Make-style order-only dependencies
Previously, the implementation of order-only dependencies differed between Make and Ninja in two important ways: 1) If the order-only dependency existed but was out of date, it would never be rebuilt, whereas Make would always rebuild out of date order-only dependencies. 2) If the order-only dependency did not exist, it would cause its reverse dependencies to always build, whereas Make would only rebuild a file if a non-order-only dependency was out of date. A key distinction between Ninja and Make as seen through the above two points was that in Ninja, order-only dependencies cared about whether the target as a file exists (so perhaps a better name for the old semantics would have been "missing-only dependencies"). These differences made it impossible to introduce an order-only dependency on an always out-of-date (i.e. missing) target without also causing the depender and its reverse dependencies to rebuild unnecessarily on every build. Build systems which must perform some action (such as logging the build start time, or printing a message) at the start of every build typically implement this by adding to every target an order-only dependency which performs this action, which would have forced an entire rebuild on every invocation of Ninja under the old semantics. This commit causes Ninja to conform to the Make-style behaviour.
Diffstat (limited to 'src/build_test.cc')
-rw-r--r--src/build_test.cc47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/build_test.cc b/src/build_test.cc
index a4bf256..4544e2c 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -532,6 +532,53 @@ TEST_F(BuildTest, OrderOnlyDeps) {
ASSERT_EQ(1u, commands_ran_.size());
}
+TEST_F(BuildTest, RebuildOrderOnlyDeps) {
+ string err;
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"rule cc\n command = cc $in\n"
+"rule true\n command = true\n"
+"build oo.h: cc oo.h.in\n"
+"build foo.o: cc foo.c || oo.h\n"));
+
+ fs_.Create("foo.c", now_, "");
+ fs_.Create("oo.h.in", now_, "");
+
+ // foo.o and order-only dep dirty, build both.
+ EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ("", err);
+ ASSERT_EQ(2u, commands_ran_.size());
+
+ // all clean, no rebuild.
+ commands_ran_.clear();
+ state_.Reset();
+ EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
+ EXPECT_EQ("", err);
+ EXPECT_TRUE(builder_.AlreadyUpToDate());
+
+ // order-only dep missing, build it only.
+ fs_.RemoveFile("oo.h");
+ commands_ran_.clear();
+ state_.Reset();
+ EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ("", err);
+ ASSERT_EQ(1u, commands_ran_.size());
+ ASSERT_EQ("cc oo.h.in", commands_ran_[0]);
+
+ now_++;
+
+ // order-only dep dirty, build it only.
+ fs_.Create("oo.h.in", now_, "");
+ commands_ran_.clear();
+ state_.Reset();
+ EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
+ EXPECT_TRUE(builder_.Build(&err));
+ ASSERT_EQ("", err);
+ ASSERT_EQ(1u, commands_ran_.size());
+ ASSERT_EQ("cc oo.h.in", commands_ran_[0]);
+}
+
TEST_F(BuildTest, Phony) {
string err;
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,