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
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_+.
~~~~~~~~~~~~~~~~~~
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
~~~~~~~~~~~~~~~~~~~~~~
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");
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";
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_;
}
// 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 (;;) {
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;
}
}
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;
EQUALS,
COLON,
PIPE,
+ PIPE2,
INDENT,
OUTDENT,
TEOF
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) {