From: Evan Martin Date: Sun, 23 Jan 2011 04:51:52 +0000 (-0800) Subject: allow implicit deps X-Git-Tag: release-120715~512 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a206206f3ff6c118f89cce04bf39f424bd1a6510;p=platform%2Fupstream%2Fninja.git allow implicit deps --- 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::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) {