v1.8.2
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index d54e097..17d607a 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -1,6 +1,6 @@
The Ninja build system
======================
-v1.8.1, Sep 2017
+v1.8.2, Sep 2017
Introduction
diff --git a/src/build_log_perftest.cc b/src/build_log_perftest.cc
index b4efb1d..e471d13 100644
--- a/src/build_log_perftest.cc
+++ b/src/build_log_perftest.cc
@@ -71,7 +71,7 @@
long_rule_command += "$in -o $out\n";
State state;
- ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, NULL);
if (!parser.ParseTest("rule cxx\n command = " + long_rule_command, err))
return false;
diff --git a/src/build_test.cc b/src/build_test.cc
index a0f898f..46ab33e 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -1068,6 +1068,19 @@
EXPECT_TRUE(builder_.AlreadyUpToDate());
}
+// Test a self-referencing phony. Ideally this should not work, but
+// ninja 1.7 and below tolerated and CMake 2.8.12.x and 3.0.x both
+// incorrectly produce it. We tolerate it for compatibility.
+TEST_F(BuildTest, PhonySelfReference) {
+ string err;
+ ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
+"build a: phony a\n"));
+
+ EXPECT_TRUE(builder_.AddTarget("a", &err));
+ ASSERT_EQ("", err);
+ EXPECT_TRUE(builder_.AlreadyUpToDate());
+}
+
TEST_F(BuildTest, Fail) {
ASSERT_NO_FATAL_FAILURE(AssertParse(&state_,
"rule fail\n"
diff --git a/src/graph.cc b/src/graph.cc
index 7dd9491..ce4ea77 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -170,6 +170,13 @@
err->append(" -> ");
}
err->append((*start)->path());
+
+ if ((start + 1) == stack->end() && edge->maybe_phonycycle_diagnostic()) {
+ // The manifest parser would have filtered out the self-referencing
+ // input if it were not configured to allow the error.
+ err->append(" [-w phonycycle=err]");
+ }
+
return false;
}
@@ -410,6 +417,14 @@
return pool() == &State::kConsolePool;
}
+bool Edge::maybe_phonycycle_diagnostic() const {
+ // CMake 2.8.12.x and 3.0.x produced self-referencing phony rules
+ // of the form "build a: phony ... a ...". Restrict our
+ // "phonycycle" diagnostic option to the form it used.
+ return is_phony() && outputs_.size() == 1 && implicit_outs_ == 0 &&
+ implicit_deps_ == 0;
+}
+
// static
string Node::PathDecanonicalized(const string& path, uint64_t slash_bits) {
string result = path;
diff --git a/src/graph.h b/src/graph.h
index 586c588..a8f0641 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -201,6 +201,7 @@
bool is_phony() const;
bool use_console() const;
+ bool maybe_phonycycle_diagnostic() const;
};
diff --git a/src/graph_test.cc b/src/graph_test.cc
index d4d2824..422bc9a 100644
--- a/src/graph_test.cc
+++ b/src/graph_test.cc
@@ -323,6 +323,18 @@
ASSERT_FALSE(plan_.more_to_do());
}
+TEST_F(GraphTest, PhonySelfReferenceError) {
+ ManifestParserOptions parser_opts;
+ parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
+ AssertParse(&state_,
+"build a: phony a\n",
+ parser_opts);
+
+ string err;
+ EXPECT_FALSE(scan_.RecomputeDirty(GetNode("a"), &err));
+ ASSERT_EQ("dependency cycle: a -> a [-w phonycycle=err]", err);
+}
+
TEST_F(GraphTest, DependencyCycle) {
AssertParse(&state_,
"build out: cat mid\n"
diff --git a/src/manifest_parser.cc b/src/manifest_parser.cc
index 2164921..27c423b 100644
--- a/src/manifest_parser.cc
+++ b/src/manifest_parser.cc
@@ -26,9 +26,9 @@
#include "version.h"
ManifestParser::ManifestParser(State* state, FileReader* file_reader,
- DupeEdgeAction dupe_edge_action)
+ ManifestParserOptions options)
: state_(state), file_reader_(file_reader),
- dupe_edge_action_(dupe_edge_action), quiet_(false) {
+ options_(options), quiet_(false) {
env_ = &state->bindings_;
}
@@ -346,7 +346,7 @@
if (!CanonicalizePath(&path, &slash_bits, &path_err))
return lexer_.Error(path_err, err);
if (!state_->AddOut(edge, path, slash_bits)) {
- if (dupe_edge_action_ == kDupeEdgeActionError) {
+ if (options_.dupe_edge_action_ == kDupeEdgeActionError) {
lexer_.Error("multiple rules generate " + path + " [-w dupbuild=err]",
err);
return false;
@@ -383,6 +383,25 @@
edge->implicit_deps_ = implicit;
edge->order_only_deps_ = order_only;
+ if (options_.phony_cycle_action_ == kPhonyCycleActionWarn &&
+ edge->maybe_phonycycle_diagnostic()) {
+ // CMake 2.8.12.x and 3.0.x incorrectly write phony build statements
+ // that reference themselves. Ninja used to tolerate these in the
+ // build graph but that has since been fixed. Filter them out to
+ // support users of those old CMake versions.
+ Node* out = edge->outputs_[0];
+ vector<Node*>::iterator new_end =
+ remove(edge->inputs_.begin(), edge->inputs_.end(), out);
+ if (new_end != edge->inputs_.end()) {
+ edge->inputs_.erase(new_end, edge->inputs_.end());
+ if (!quiet_) {
+ Warning("phony target '%s' names itself as an input; "
+ "ignoring [-w phonycycle=warn]",
+ out->path().c_str());
+ }
+ }
+ }
+
// Multiple outputs aren't (yet?) supported with depslog.
string deps_type = edge->GetBinding("deps");
if (!deps_type.empty() && edge->outputs_.size() > 1) {
@@ -400,7 +419,7 @@
return false;
string path = eval.Evaluate(env_);
- ManifestParser subparser(state_, file_reader_, dupe_edge_action_);
+ ManifestParser subparser(state_, file_reader_, options_);
if (new_scope) {
subparser.env_ = new BindingEnv(env_);
} else {
diff --git a/src/manifest_parser.h b/src/manifest_parser.h
index 043e4b2..2136018 100644
--- a/src/manifest_parser.h
+++ b/src/manifest_parser.h
@@ -31,10 +31,23 @@
kDupeEdgeActionError,
};
+enum PhonyCycleAction {
+ kPhonyCycleActionWarn,
+ kPhonyCycleActionError,
+};
+
+struct ManifestParserOptions {
+ ManifestParserOptions()
+ : dupe_edge_action_(kDupeEdgeActionWarn),
+ phony_cycle_action_(kPhonyCycleActionWarn) {}
+ DupeEdgeAction dupe_edge_action_;
+ PhonyCycleAction phony_cycle_action_;
+};
+
/// Parses .ninja files.
struct ManifestParser {
ManifestParser(State* state, FileReader* file_reader,
- DupeEdgeAction dupe_edge_action);
+ ManifestParserOptions options = ManifestParserOptions());
/// Load and parse a file.
bool Load(const string& filename, string* err, Lexer* parent = NULL);
@@ -67,7 +80,7 @@
BindingEnv* env_;
FileReader* file_reader_;
Lexer lexer_;
- DupeEdgeAction dupe_edge_action_;
+ ManifestParserOptions options_;
bool quiet_;
};
diff --git a/src/manifest_parser_perftest.cc b/src/manifest_parser_perftest.cc
index 60c2054..67d11f9 100644
--- a/src/manifest_parser_perftest.cc
+++ b/src/manifest_parser_perftest.cc
@@ -56,7 +56,7 @@
string err;
RealDiskInterface disk_interface;
State state;
- ManifestParser parser(&state, &disk_interface, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, &disk_interface);
if (!parser.Load("build.ninja", &err)) {
fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
exit(1);
diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc
index 3c82dc5..39ed810 100644
--- a/src/manifest_parser_test.cc
+++ b/src/manifest_parser_test.cc
@@ -23,7 +23,7 @@
struct ParserTest : public testing::Test {
void AssertParse(const char* input) {
- ManifestParser parser(&state, &fs_, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, &fs_);
string err;
EXPECT_TRUE(parser.ParseTest(input, &err));
ASSERT_EQ("", err);
@@ -358,7 +358,9 @@
"build out1 out2: cat in1\n"
"build out1: cat in2\n"
"build final: cat out1\n";
- ManifestParser parser(&state, &fs_, kDupeEdgeActionError);
+ ManifestParserOptions parser_opts;
+ parser_opts.dupe_edge_action_ = kDupeEdgeActionError;
+ ManifestParser parser(&state, &fs_, parser_opts);
string err;
EXPECT_FALSE(parser.ParseTest(kInput, &err));
EXPECT_EQ("input:5: multiple rules generate out1 [-w dupbuild=err]\n", err);
@@ -373,13 +375,41 @@
"build final: cat out1\n");
const char kInput[] =
"subninja sub.ninja\n";
- ManifestParser parser(&state, &fs_, kDupeEdgeActionError);
+ ManifestParserOptions parser_opts;
+ parser_opts.dupe_edge_action_ = kDupeEdgeActionError;
+ ManifestParser parser(&state, &fs_, parser_opts);
string err;
EXPECT_FALSE(parser.ParseTest(kInput, &err));
EXPECT_EQ("sub.ninja:5: multiple rules generate out1 [-w dupbuild=err]\n",
err);
}
+TEST_F(ParserTest, PhonySelfReferenceIgnored) {
+ ASSERT_NO_FATAL_FAILURE(AssertParse(
+"build a: phony a\n"
+));
+
+ Node* node = state.LookupNode("a");
+ Edge* edge = node->in_edge();
+ ASSERT_TRUE(edge->inputs_.empty());
+}
+
+TEST_F(ParserTest, PhonySelfReferenceKept) {
+ const char kInput[] =
+"build a: phony a\n";
+ ManifestParserOptions parser_opts;
+ parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
+ ManifestParser parser(&state, &fs_, parser_opts);
+ string err;
+ EXPECT_TRUE(parser.ParseTest(kInput, &err));
+ EXPECT_EQ("", err);
+
+ Node* node = state.LookupNode("a");
+ Edge* edge = node->in_edge();
+ ASSERT_EQ(edge->inputs_.size(), 1);
+ ASSERT_EQ(edge->inputs_[0], node);
+}
+
TEST_F(ParserTest, ReservedWords) {
ASSERT_NO_FATAL_FAILURE(AssertParse(
"rule build\n"
@@ -391,7 +421,7 @@
TEST_F(ParserTest, Errors) {
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest(string("subn", 4), &err));
EXPECT_EQ("input:1: expected '=', got eof\n"
@@ -402,7 +432,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("foobar", &err));
EXPECT_EQ("input:1: expected '=', got eof\n"
@@ -413,7 +443,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("x 3", &err));
EXPECT_EQ("input:1: expected '=', got identifier\n"
@@ -424,7 +454,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("x = 3", &err));
EXPECT_EQ("input:1: unexpected EOF\n"
@@ -435,7 +465,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("x = 3\ny 2", &err));
EXPECT_EQ("input:2: expected '=', got identifier\n"
@@ -446,7 +476,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("x = $", &err));
EXPECT_EQ("input:1: bad $-escape (literal $ must be written as $$)\n"
@@ -457,7 +487,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("x = $\n $[\n", &err));
EXPECT_EQ("input:2: bad $-escape (literal $ must be written as $$)\n"
@@ -468,7 +498,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("x = a$\n b$\n $\n", &err));
EXPECT_EQ("input:4: unexpected EOF\n"
@@ -477,7 +507,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("build\n", &err));
EXPECT_EQ("input:1: expected path\n"
@@ -488,7 +518,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("build x: y z\n", &err));
EXPECT_EQ("input:1: unknown build rule 'y'\n"
@@ -499,7 +529,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("build x:: y z\n", &err));
EXPECT_EQ("input:1: expected build command name\n"
@@ -510,7 +540,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n command = cat ok\n"
"build x: cat $\n :\n",
@@ -523,7 +553,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n",
&err));
@@ -532,7 +562,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = echo\n"
@@ -546,7 +576,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = echo\n"
@@ -558,7 +588,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = ${fafsd\n"
@@ -573,7 +603,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = cat\n"
@@ -588,7 +618,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cat\n"
" command = cat\n"
@@ -602,7 +632,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule %foo\n",
&err));
@@ -611,7 +641,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n"
" command = foo\n"
@@ -625,7 +655,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n"
"build $.: cc bar.cc\n",
@@ -638,7 +668,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n && bar",
&err));
@@ -647,7 +677,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n"
"build $: cc bar.cc\n",
@@ -660,7 +690,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("default\n",
&err));
@@ -672,7 +702,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("default nonexistent\n",
&err));
@@ -684,7 +714,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule r\n command = r\n"
"build b: r\n"
@@ -698,7 +728,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("default $a\n", &err));
EXPECT_EQ("input:1: empty path\n"
@@ -709,7 +739,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule r\n"
" command = r\n"
@@ -721,7 +751,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
// the indented blank line must terminate the rule
// this also verifies that "unexpected (token)" errors are correct
@@ -734,7 +764,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("pool\n", &err));
EXPECT_EQ("input:1: expected pool name\n", err);
@@ -742,7 +772,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n", &err));
EXPECT_EQ("input:2: expected 'depth =' line\n", err);
@@ -750,7 +780,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n"
" depth = 4\n"
@@ -763,7 +793,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n"
" depth = -1\n", &err));
@@ -775,7 +805,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("pool foo\n"
" bar = 1\n", &err));
@@ -787,7 +817,7 @@
{
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
// Pool names are dereferenced at edge parsing time.
EXPECT_FALSE(parser.ParseTest("rule run\n"
@@ -800,7 +830,7 @@
TEST_F(ParserTest, MissingInput) {
State local_state;
- ManifestParser parser(&local_state, &fs_, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, &fs_);
string err;
EXPECT_FALSE(parser.Load("build.ninja", &err));
EXPECT_EQ("loading 'build.ninja': No such file or directory", err);
@@ -808,7 +838,7 @@
TEST_F(ParserTest, MultipleOutputs) {
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_TRUE(parser.ParseTest("rule cc\n command = foo\n depfile = bar\n"
"build a.o b.o: cc c.cc\n",
@@ -818,7 +848,7 @@
TEST_F(ParserTest, MultipleOutputsWithDeps) {
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_FALSE(parser.ParseTest("rule cc\n command = foo\n deps = gcc\n"
"build a.o b.o: cc c.cc\n",
@@ -853,7 +883,7 @@
}
TEST_F(ParserTest, MissingSubNinja) {
- ManifestParser parser(&state, &fs_, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, &fs_);
string err;
EXPECT_FALSE(parser.ParseTest("subninja foo.ninja\n", &err));
EXPECT_EQ("input:1: loading 'foo.ninja': No such file or directory\n"
@@ -866,7 +896,7 @@
// Test that rules are scoped to subninjas.
fs_.Create("test.ninja", "rule cat\n"
" command = cat\n");
- ManifestParser parser(&state, &fs_, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, &fs_);
string err;
EXPECT_TRUE(parser.ParseTest("rule cat\n"
" command = cat\n"
@@ -879,7 +909,7 @@
" command = cat\n");
fs_.Create("test.ninja", "include rules.ninja\n"
"build x : cat\n");
- ManifestParser parser(&state, &fs_, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, &fs_);
string err;
EXPECT_TRUE(parser.ParseTest("include rules.ninja\n"
"subninja test.ninja\n"
@@ -899,7 +929,7 @@
TEST_F(ParserTest, BrokenInclude) {
fs_.Create("include.ninja", "build\n");
- ManifestParser parser(&state, &fs_, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, &fs_);
string err;
EXPECT_FALSE(parser.ParseTest("include include.ninja\n", &err));
EXPECT_EQ("include.ninja:1: expected path\n"
@@ -974,7 +1004,7 @@
}
TEST_F(ParserTest, NoExplicitOutput) {
- ManifestParser parser(&state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&state, NULL);
string err;
EXPECT_TRUE(parser.ParseTest(
"rule cat\n"
@@ -1034,7 +1064,7 @@
TEST_F(ParserTest, CRLF) {
State local_state;
- ManifestParser parser(&local_state, NULL, kDupeEdgeActionWarn);
+ ManifestParser parser(&local_state, NULL);
string err;
EXPECT_TRUE(parser.ParseTest("# comment with crlf\r\n", &err));
diff --git a/src/ninja.cc b/src/ninja.cc
index 54de7b9..ed004ac 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -70,6 +70,9 @@
/// Whether duplicate rules for one target should warn or print an error.
bool dupe_edges_should_err;
+
+ /// Whether phony cycles should warn or print an error.
+ bool phony_cycle_should_err;
};
/// The Ninja main() loads up a series of data structures; various tools need
@@ -845,7 +848,8 @@
bool WarningEnable(const string& name, Options* options) {
if (name == "list") {
printf("warning flags:\n"
-" dupbuild={err,warn} multiple build lines for one target\n");
+" dupbuild={err,warn} multiple build lines for one target\n"
+" phonycycle={err,warn} phony build statement references itself\n");
return false;
} else if (name == "dupbuild=err") {
options->dupe_edges_should_err = true;
@@ -853,9 +857,16 @@
} else if (name == "dupbuild=warn") {
options->dupe_edges_should_err = false;
return true;
+ } else if (name == "phonycycle=err") {
+ options->phony_cycle_should_err = true;
+ return true;
+ } else if (name == "phonycycle=warn") {
+ options->phony_cycle_should_err = false;
+ return true;
} else {
const char* suggestion =
- SpellcheckString(name.c_str(), "dupbuild=err", "dupbuild=warn", NULL);
+ SpellcheckString(name.c_str(), "dupbuild=err", "dupbuild=warn",
+ "phonycycle=err", "phonycycle=warn", NULL);
if (suggestion) {
Error("unknown warning flag '%s', did you mean '%s'?",
name.c_str(), suggestion);
@@ -1144,10 +1155,14 @@
for (int cycle = 1; cycle <= kCycleLimit; ++cycle) {
NinjaMain ninja(ninja_command, config);
- ManifestParser parser(&ninja.state_, &ninja.disk_interface_,
- options.dupe_edges_should_err
- ? kDupeEdgeActionError
- : kDupeEdgeActionWarn);
+ ManifestParserOptions parser_opts;
+ if (options.dupe_edges_should_err) {
+ parser_opts.dupe_edge_action_ = kDupeEdgeActionError;
+ }
+ if (options.phony_cycle_should_err) {
+ parser_opts.phony_cycle_action_ = kPhonyCycleActionError;
+ }
+ ManifestParser parser(&ninja.state_, &ninja.disk_interface_, parser_opts);
string err;
if (!parser.Load(options.input_file, &err)) {
Error("%s", err.c_str());
diff --git a/src/test.cc b/src/test.cc
index 51882f0..a9816bc 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -95,8 +95,9 @@
return state_.GetNode(path, 0);
}
-void AssertParse(State* state, const char* input) {
- ManifestParser parser(state, NULL, kDupeEdgeActionWarn);
+void AssertParse(State* state, const char* input,
+ ManifestParserOptions opts) {
+ ManifestParser parser(state, NULL, opts);
string err;
EXPECT_TRUE(parser.ParseTest(input, &err));
ASSERT_EQ("", err);
diff --git a/src/test.h b/src/test.h
index 02ed929..3bce8f7 100644
--- a/src/test.h
+++ b/src/test.h
@@ -16,6 +16,7 @@
#define NINJA_TEST_H_
#include "disk_interface.h"
+#include "manifest_parser.h"
#include "state.h"
#include "util.h"
@@ -122,7 +123,8 @@
State state_;
};
-void AssertParse(State* state, const char* input);
+void AssertParse(State* state, const char* input,
+ ManifestParserOptions = ManifestParserOptions());
void AssertHash(const char* expected, uint64_t actual);
void VerifyGraph(const State& state);
diff --git a/src/version.cc b/src/version.cc
index e2a9f49..3a20205 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -18,7 +18,7 @@
#include "util.h"
-const char* kNinjaVersion = "1.8.1";
+const char* kNinjaVersion = "1.8.2";
void ParseVersion(const string& version, int* major, int* minor) {
size_t end = version.find('.');