summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2011-01-23 04:51:52 (GMT)
committerEvan Martin <martine@danga.com>2011-01-23 04:51:52 (GMT)
commita206206f3ff6c118f89cce04bf39f424bd1a6510 (patch)
treefad94b150e9d2bed7fdc48ec80d5f180e1298982
parentc1cb4f5ee82b1d41a5fb028aea0c6daa0461f050 (diff)
downloadNinja-a206206f3ff6c118f89cce04bf39f424bd1a6510.zip
Ninja-a206206f3ff6c118f89cce04bf39f424bd1a6510.tar.gz
Ninja-a206206f3ff6c118f89cce04bf39f424bd1a6510.tar.bz2
allow implicit deps
-rw-r--r--build.ninja4
-rw-r--r--manual.asciidoc39
-rw-r--r--src/build_test.cc2
-rw-r--r--src/parsers.cc26
-rw-r--r--src/parsers.h1
-rw-r--r--src/parsers_test.cc14
6 files changed, 66 insertions, 20 deletions
diff --git a/build.ninja b/build.ninja
index 1a3c6b3..f49a306 100644
--- a/build.ninja
+++ b/build.ninja
@@ -80,8 +80,8 @@ rule asciidoc
description = ASCIIDOC $in
build manual.html: asciidoc manual.asciidoc
-build doc: phony | manual.html
+build doc: phony || manual.html
# Use the built-in phony rule and an order-only dependency
# to make building "all" build all targets.
-build all: phony | ninja ninja_test graph.png doc
+build all: phony || ninja ninja_test graph.png doc
diff --git a/manual.asciidoc b/manual.asciidoc
index 258782c..1f98b6f 100644
--- a/manual.asciidoc
+++ b/manual.asciidoc
@@ -219,7 +219,9 @@ 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_+. +
- Order-only dependencies may be tacked on the end with +_|
+ Implicit dependencies may be tacked on the end with +_|
+ _dependency1_ _dependency2_+.
+ Order-only dependencies may be tacked on the end with +_||
_dependency1_ _dependency2_+.
3. Variable declarations, which look like +_variable_ = _value_+.
@@ -273,22 +275,33 @@ Build dependencies
~~~~~~~~~~~~~~~~~~
There are three types of build dependencies which are subtly different.
-1. Explicit dependencies, as listed in a build line. These are
+1. _Explicit dependencies_, as listed in a build line. These are
available as the `$in` variable in the rule. Changes in these files
cause the output to be rebuilt; if these file are missing and
ninja doesn't know how to build them, the build is aborted.
++
+This is the standard form of dependency to be used for e.g. the
+source file of a compile command.
-2. Implicit dependencies, as picked up from a `depfile` attribute on
- a rule. Changes in these files cause the output to be rebuilt; if
- they are missing, they are just skipped.
-
-3. Order-only dependencies, expressed with the syntax `| dep1 dep2` on
- the end of a build line. When these are missing, the output is not
- rebuilt until they are built, but once they are available further
- changes to the files do not affect the output. Order-only
- dependencies can be useful for bootstrapping implicit dependencies:
- for example, to generate a header file before starting a subsequent
- compilation step.
+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.
++
+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 should be an implicit dependency.
+
+3. _Order-only dependencies_, expressed with the syntax +|| _dep1_
+ _dep2_+ on the end of a build line. When these are missing, the
+ output is not rebuilt until they are built, but once they are
+ available further changes to the files do not affect the output.
++
+Order-only dependencies can be useful for bootstrapping dependencies
+that are only discovered during build time: for example, to generate a
+header file before starting a subsequent compilation step. (Once the
+header is used in compilation, a generated dependency file will then
+express the implicit dependency.)
Evaluation and scoping
~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/build_test.cc b/src/build_test.cc
index 2588174..71c950b 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -469,7 +469,7 @@ 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"));
+"build foo.o: cc foo.c || otherfile\n"));
fs_.Create("foo.c", now_, "");
fs_.Create("otherfile", now_, "");
fs_.Create("foo.o.d", now_, "foo.o: blah.h bar.h\n");
diff --git a/src/parsers.cc b/src/parsers.cc
index 7b810fe..f309854 100644
--- a/src/parsers.cc
+++ b/src/parsers.cc
@@ -20,6 +20,7 @@ string Token::AsString() const {
case EQUALS: return "'='";
case COLON: return "':'";
case PIPE: return "'|'";
+ case PIPE2: return "'||'";
case TEOF: return "eof";
case INDENT: return "indenting in";
case OUTDENT: return "indenting out";
@@ -181,8 +182,13 @@ Token::Type Tokenizer::PeekToken() {
token_.type_ = Token::EQUALS;
++cur_;
} else if (*cur_ == '|') {
- token_.type_ = Token::PIPE;
- ++cur_;
+ if (cur_ + 1 < end_ && cur_[1] == '|') {
+ token_.type_ = Token::PIPE2;
+ cur_ += 2;
+ } else {
+ token_.type_ = Token::PIPE;
+ ++cur_;
+ }
} else if (*cur_ == '\n') {
token_.type_ = Token::NEWLINE;
++cur_;
@@ -413,7 +419,7 @@ bool ManifestParser::ParseEdge(string* err) {
}
// Add all order-only deps, counting how many as we go.
- int order_only = 0;
+ int implicit = 0;
if (tokenizer_.PeekToken() == Token::PIPE) {
tokenizer_.ConsumeToken();
for (;;) {
@@ -421,6 +427,19 @@ bool ManifestParser::ParseEdge(string* err) {
if (!tokenizer_.ReadIdent(&in))
break;
ins.push_back(in);
+ ++implicit;
+ }
+ }
+
+ // Add all order-only deps, counting how many as we go.
+ int order_only = 0;
+ if (tokenizer_.PeekToken() == Token::PIPE2) {
+ tokenizer_.ConsumeToken();
+ for (;;) {
+ string in;
+ if (!tokenizer_.ReadIdent(&in))
+ break;
+ ins.push_back(in);
++order_only;
}
}
@@ -467,6 +486,7 @@ bool ManifestParser::ParseEdge(string* err) {
state_->AddIn(edge, *i);
for (vector<string>::iterator i = outs.begin(); i != outs.end(); ++i)
state_->AddOut(edge, *i);
+ edge->implicit_deps_ = implicit;
edge->order_only_deps_ = order_only;
return true;
diff --git a/src/parsers.h b/src/parsers.h
index ec9a677..55417cd 100644
--- a/src/parsers.h
+++ b/src/parsers.h
@@ -21,6 +21,7 @@ struct Token {
EQUALS,
COLON,
PIPE,
+ PIPE2,
INDENT,
OUTDENT,
TEOF
diff --git a/src/parsers_test.cc b/src/parsers_test.cc
index 82ef8f3..1ba34da 100644
--- a/src/parsers_test.cc
+++ b/src/parsers_test.cc
@@ -289,10 +289,22 @@ TEST_F(ParserTest, Include) {
EXPECT_EQ("inner", state.bindings_.LookupVariable("var"));
}
-TEST_F(ParserTest, OrderOnly) {
+TEST_F(ParserTest, Implicit) {
ASSERT_NO_FATAL_FAILURE(AssertParse(
"rule cat\n command = cat $in > $out\n"
"build foo: cat bar | baz\n"));
+
+ Edge* edge = state.LookupNode("foo")->in_edge_;
+ ASSERT_TRUE(edge->is_implicit(1));
+}
+
+TEST_F(ParserTest, OrderOnly) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(
+"rule cat\n command = cat $in > $out\n"
+"build foo: cat bar || baz\n"));
+
+ Edge* edge = state.LookupNode("foo")->in_edge_;
+ ASSERT_TRUE(edge->is_order_only(1));
}
TEST(MakefileParser, Basic) {