mirror of
https://github.com/reactos/ninja.git
synced 2025-02-18 18:47:58 +00:00
SEMANTIC CHANGE: implicit inputs are now required to exist
Edges found through depfiles are special: they get an extra empty "phony" rule. (This is identical to the way you hack this with Makefiles.)
This commit is contained in:
parent
400ca686fe
commit
54ae1a37ea
@ -353,9 +353,11 @@ A file is a series of declarations. A declaration can be one of:
|
||||
2. A build edge, which looks like +build _output1_ _output2_:
|
||||
_rulename_ _input1_ _input2_+. +
|
||||
Implicit dependencies may be tacked on the end with +|
|
||||
_dependency1_ _dependency2_+.
|
||||
_dependency1_ _dependency2_+. +
|
||||
Order-only dependencies may be tacked on the end with +||
|
||||
_dependency1_ _dependency2_+.
|
||||
_dependency1_ _dependency2_+. (See <<ref_dependencies,the reference on
|
||||
dependency types>>.)
|
||||
|
||||
|
||||
3. Variable declarations, which look like +_variable_ = _value_+.
|
||||
|
||||
@ -386,7 +388,7 @@ keys.
|
||||
interpretation by Ninja.
|
||||
|
||||
`depfile`:: path to an optional `Makefile` that contains extra
|
||||
_implicit dependencies_ (see the <<ref_dependencies,the reference on
|
||||
_implicit dependencies_ (see <<ref_dependencies,the reference on
|
||||
dependency types>>). This is explicitly to support `gcc` and its `-M`
|
||||
family of flags, which output the list of headers a given `.c` file
|
||||
depends on.
|
||||
@ -398,6 +400,11 @@ rule cc
|
||||
depfile = $out.d
|
||||
command = gcc -MMD -MF $out.d [other gcc flags here]
|
||||
----
|
||||
+
|
||||
When loading a `depfile`, Ninja implicitly adds edges such that it is
|
||||
not an error if the listed dependency is missing. This allows you to
|
||||
delete a depfile-discovered header file and rebuild, without the build
|
||||
aborting due to a missing input.
|
||||
|
||||
|
||||
`description`:: a short description of the command, used to pretty-print
|
||||
@ -425,14 +432,17 @@ source file of a compile command.
|
||||
|
||||
2. _Implicit dependencies_, either as picked up from
|
||||
a `depfile` attribute on a rule or from the syntax +| _dep1_
|
||||
_dep2_+ on the end of a build line. Changes in these files cause
|
||||
the output to be rebuilt; if they are missing, they are just
|
||||
skipped.
|
||||
_dep2_+ on the end of a build line. The semantics are identical to
|
||||
explicit dependencies, the only difference is that implicit dependencies
|
||||
don't show up in the `$in` variable.
|
||||
+
|
||||
This is for expressing dependencies that don't show up on the
|
||||
command line of the command; for example, for a rule that runs a
|
||||
script, the script itself should be an implicit dependency, as
|
||||
changes to the script should cause the output to rebuild.
|
||||
+
|
||||
Note that dependencies as loaded through depfiles have slightly different
|
||||
semantics, as described in the <<ref_rule,rule reference>>.
|
||||
|
||||
3. _Order-only dependencies_, expressed with the syntax +|| _dep1_
|
||||
_dep2_+ on the end of a build line. When these are missing, the
|
||||
|
@ -194,8 +194,7 @@ bool Plan::AddSubTarget(Node* node, vector<Node*>* stack, string* err) {
|
||||
bool awaiting_inputs = false;
|
||||
for (vector<Node*>::iterator i = edge->inputs_.begin();
|
||||
i != edge->inputs_.end(); ++i) {
|
||||
if (!edge->is_implicit(i - edge->inputs_.begin()) &&
|
||||
AddSubTarget(*i, stack, err)) {
|
||||
if (AddSubTarget(*i, stack, err)) {
|
||||
awaiting_inputs = true;
|
||||
} else if (!err->empty()) {
|
||||
return false;
|
||||
|
@ -428,6 +428,8 @@ TEST_F(BuildTest, DepFileOK) {
|
||||
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
|
||||
"rule cc\n command = cc $in\n depfile = $out.d\n"
|
||||
"build foo.o: cc foo.c\n"));
|
||||
Edge* edge = state_.edges_.back();
|
||||
|
||||
fs_.Create("foo.c", now_, "");
|
||||
GetNode("bar.h")->dirty_ = true; // Mark bar.h as missing.
|
||||
fs_.Create("foo.o.d", now_, "foo.o: blah.h bar.h\n");
|
||||
@ -436,9 +438,10 @@ TEST_F(BuildTest, DepFileOK) {
|
||||
ASSERT_EQ(1u, fs_.files_read_.size());
|
||||
EXPECT_EQ("foo.o.d", fs_.files_read_[0]);
|
||||
|
||||
// Expect three new edges: one generating foo.o, and two more from
|
||||
// loading the depfile.
|
||||
ASSERT_EQ(orig_edges + 3, (int)state_.edges_.size());
|
||||
// Expect our edge to now have three inputs: foo.c and two headers.
|
||||
ASSERT_EQ(orig_edges + 1, (int)state_.edges_.size());
|
||||
Edge* edge = state_.edges_.back();
|
||||
ASSERT_EQ(3u, edge->inputs_.size());
|
||||
|
||||
// Expect the command line we generate to only use the original input.
|
||||
@ -461,13 +464,14 @@ TEST_F(BuildTest, OrderOnlyDeps) {
|
||||
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"));
|
||||
Edge* edge = state_.edges_.back();
|
||||
|
||||
fs_.Create("foo.c", now_, "");
|
||||
fs_.Create("otherfile", now_, "");
|
||||
fs_.Create("foo.o.d", now_, "foo.o: blah.h bar.h\n");
|
||||
EXPECT_TRUE(builder_.AddTarget("foo.o", &err));
|
||||
ASSERT_EQ("", err);
|
||||
|
||||
Edge* edge = state_.edges_.back();
|
||||
// One explicit, two implicit, one order only.
|
||||
ASSERT_EQ(4u, edge->inputs_.size());
|
||||
EXPECT_EQ(2, edge->implicit_deps_);
|
||||
|
13
src/graph.cc
13
src/graph.cc
@ -43,9 +43,7 @@ bool Edge::RecomputeDirty(State* state, DiskInterface* disk_interface,
|
||||
return false;
|
||||
} else {
|
||||
// This input has no in-edge; it is dirty if it is missing.
|
||||
// But it's ok for implicit deps to be missing.
|
||||
if (!is_implicit(i - inputs_.begin()))
|
||||
(*i)->dirty_ = !(*i)->file_->exists();
|
||||
(*i)->dirty_ = !(*i)->file_->exists();
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,6 +163,15 @@ bool Edge::LoadDepFile(State* state, DiskInterface* disk_interface,
|
||||
inputs_.insert(inputs_.end() - order_only_deps_, node);
|
||||
node->out_edges_.push_back(this);
|
||||
++implicit_deps_;
|
||||
|
||||
// If we don't have a edge that generates this input already,
|
||||
// create one; this makes us not abort if the input is missing,
|
||||
// but instead will rebuild in that circumstance.
|
||||
if (!node->in_edge_) {
|
||||
Edge* phony_edge = state->AddEdge(&State::kPhonyRule);
|
||||
node->in_edge_ = phony_edge;
|
||||
phony_edge->outputs_.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -31,8 +31,26 @@ TEST_F(GraphTest, MissingImplicit) {
|
||||
EXPECT_TRUE(edge->RecomputeDirty(&state_, &fs_, &err));
|
||||
ASSERT_EQ("", err);
|
||||
|
||||
// A missing implicit dep does not make the output dirty.
|
||||
EXPECT_FALSE(GetNode("out")->dirty_);
|
||||
// A missing implicit dep *should* make the output dirty.
|
||||
// (In fact, a build will fail.)
|
||||
// This is a change from prior semantics of ninja.
|
||||
EXPECT_TRUE(GetNode("out")->dirty_);
|
||||
}
|
||||
|
||||
TEST_F(GraphTest, ModifiedImplicit) {
|
||||
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
|
||||
"build out: cat in | implicit\n"));
|
||||
fs_.Create("in", 1, "");
|
||||
fs_.Create("out", 1, "");
|
||||
fs_.Create("implicit", 2, "");
|
||||
|
||||
Edge* edge = GetNode("out")->in_edge_;
|
||||
string err;
|
||||
EXPECT_TRUE(edge->RecomputeDirty(&state_, &fs_, &err));
|
||||
ASSERT_EQ("", err);
|
||||
|
||||
// A modified implicit dep should make the output dirty.
|
||||
EXPECT_TRUE(GetNode("out")->dirty_);
|
||||
}
|
||||
|
||||
TEST_F(GraphTest, FunkyMakefilePath) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user