From 3fc91bb2d50990d0646da03fdb27136730543306 Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Sat, 6 Nov 2010 21:37:35 -0700 Subject: [PATCH] hack in order only deps --- ninja_jumble.cc | 16 ++++++++++++---- ninja_test.cc | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/ninja_jumble.cc b/ninja_jumble.cc index 581c24d..480e6ba 100644 --- a/ninja_jumble.cc +++ b/ninja_jumble.cc @@ -128,10 +128,15 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface, string* e (*i)->dirty_ = !(*i)->file_->exists(); } } - if ((*i)->dirty_) + + // If an input is dirty (or missing), we're dirty. + // Otherwise consider mtime, but only if it's not an order-only dep. + if ((*i)->dirty_) { dirty = true; - else if ((*i)->file_->mtime_ > most_recent_input) + } else if (i - inputs_.begin() >= ((int)inputs_.size()) - order_only_deps_ && + (*i)->file_->mtime_ > most_recent_input) { most_recent_input = (*i)->file_->mtime_; + } } assert(!outputs_.empty()); @@ -148,6 +153,8 @@ void Edge::MarkDirty(Node* node) { vector::iterator i = find(inputs_.begin(), inputs_.end(), node); if (i == inputs_.end()) return; + if (i - inputs_.begin() >= ((int)inputs_.size()) - order_only_deps_) + return; // Order-only deps don't cause us to become dirty. for (i = outputs_.begin(); i != outputs_.end(); ++i) (*i)->MarkDirty(); } @@ -157,7 +164,8 @@ struct EdgeEnv : public EvalString::Env { virtual string Evaluate(const string& var) { string result; if (var == "in") { - int explicit_deps = edge_->inputs_.size() - edge_->implicit_deps_; + int explicit_deps = edge_->inputs_.size() - edge_->implicit_deps_ - + edge_->order_only_deps_; for (vector::iterator i = edge_->inputs_.begin(); i != edge_->inputs_.end() && explicit_deps; ++i, --explicit_deps) { if (!result.empty()) @@ -240,7 +248,7 @@ bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface, string* err) } } if (node) { - inputs_.push_back(node); + inputs_.insert(inputs_.end() - order_only_deps_, node); node->out_edges_.push_back(this); ++implicit_deps_; } diff --git a/ninja_test.cc b/ninja_test.cc index 1a3626c..d7bab66 100644 --- a/ninja_test.cc +++ b/ninja_test.cc @@ -141,7 +141,7 @@ void BuildTest::Touch(const string& path) { bool BuildTest::RunCommand(Edge* edge) { commands_ran_.push_back(edge->EvaluateCommand()); - if (edge->rule_->name_ == "cat") { + if (edge->rule_->name_ == "cat" || edge->rule_->name_ == "cc") { for (vector::iterator out = edge->outputs_.begin(); out != edge->outputs_.end(); ++out) { (*out)->file_->Touch(now_); @@ -320,6 +320,51 @@ TEST_F(BuildTest, DepFileParseError) { EXPECT_EQ("line 1, col 7: expected ':', got 'blah.h'", err); } +TEST_F(BuildTest, OrderOnlyDeps) { + string err; + ASSERT_NO_FATAL_FAILURE(AssertParse(&state_, +"rule cc\n command = cc $in\n depfile = $out.d\n" +"build foo.o: cc foo.c | otherfile\n")); + Touch("foo.c"); + file_contents_["foo.o.d"] = "foo.o: blah.h bar.h\n"; + EXPECT_TRUE(builder_.AddTarget("foo.o", &err)); + + Edge* edge = state_.edges_.back(); + // One explicit, two implicit, one order only. + ASSERT_EQ(4, edge->inputs_.size()); + EXPECT_EQ(2, edge->implicit_deps_); + EXPECT_EQ(1, edge->order_only_deps_); + // Verify the inputs are in the order we expect + // (explicit then implicit then orderonly). + EXPECT_EQ("foo.c", edge->inputs_[0]->file_->path_); + EXPECT_EQ("blah.h", edge->inputs_[1]->file_->path_); + EXPECT_EQ("bar.h", edge->inputs_[2]->file_->path_); + EXPECT_EQ("otherfile", edge->inputs_[3]->file_->path_); + + // Expect the command line we generate to only use the original input. + ASSERT_EQ("cc foo.c", edge->EvaluateCommand()); + + // explicit dep dirty, expect a rebuild. + EXPECT_TRUE(builder_.Build(this, &err)); + ASSERT_EQ("", err); + ASSERT_EQ(1, commands_ran_.size()); + + // implicit dep dirty, expect a rebuild. + commands_ran_.clear(); + Touch("blah.h"); + EXPECT_TRUE(builder_.AddTarget("foo.o", &err)); + EXPECT_TRUE(builder_.Build(this, &err)); + ASSERT_EQ("", err); + ASSERT_EQ(1, commands_ran_.size()); + + // order only dep dirty, no rebuild. + commands_ran_.clear(); + Touch("otherfile"); + // We should fail to even add the depenency on foo.o, because + // there's nothing to do. + EXPECT_FALSE(builder_.AddTarget("foo.o", &err)); +} + struct StatTest : public StateTestWithBuiltinRules, public DiskInterface { // DiskInterface implementation. -- 2.7.4