summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--manual.asciidoc22
-rw-r--r--src/build.cc3
-rw-r--r--src/build_test.cc10
-rw-r--r--src/graph.cc13
-rw-r--r--src/graph_test.cc22
5 files changed, 54 insertions, 16 deletions
diff --git a/manual.asciidoc b/manual.asciidoc
index eefbe12..7aa000e 100644
--- a/manual.asciidoc
+++ b/manual.asciidoc
@@ -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
diff --git a/src/build.cc b/src/build.cc
index 1deb08a..3447e0d 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -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;
diff --git a/src/build_test.cc b/src/build_test.cc
index 38d2550..a7eca14 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -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_);
diff --git a/src/graph.cc b/src/graph.cc
index d953361..cb51618 100644
--- a/src/graph.cc
+++ b/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;
diff --git a/src/graph_test.cc b/src/graph_test.cc
index 9a5035c..e221089 100644
--- a/src/graph_test.cc
+++ b/src/graph_test.cc
@@ -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) {