diff options
author | Peter Collingbourne <peter@pcc.me.uk> | 2011-09-18 02:28:44 (GMT) |
---|---|---|
committer | Peter Collingbourne <peter@pcc.me.uk> | 2011-10-24 00:16:24 (GMT) |
commit | 6fc220b8b98d0a89204f144557d935feb775aeca (patch) | |
tree | f61cf2a7b574f74cf1e4a7fd0d73003f8c3d4dd2 /src/build_test.cc | |
parent | 5ff5891f5bed923b983c0f5a23c16d988d55f30e (diff) | |
download | Ninja-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.cc | 47 |
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_, |