Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 92b74c3

Browse files
committedMar 24, 2015
Add an opt-in flag to make duplicate edges an error (-w dupbuild=err).
This is step 1 on ninja-build#931. Duplicated edges will become an error by default in the future.
1 parent 6bac2fb commit 92b74c3

File tree

4 files changed

+65
-9
lines changed

4 files changed

+65
-9
lines changed
 

‎src/manifest_parser.cc

+10-4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
#include "util.h"
2525
#include "version.h"
2626

27-
ManifestParser::ManifestParser(State* state, FileReader* file_reader)
28-
: state_(state), file_reader_(file_reader), quiet_(false) {
27+
ManifestParser::ManifestParser(State* state, FileReader* file_reader,
28+
bool dupe_edge_should_err)
29+
: state_(state), file_reader_(file_reader),
30+
dupe_edge_should_err_(dupe_edge_should_err), quiet_(false) {
2931
env_ = &state->bindings_;
3032
}
3133

@@ -329,10 +331,14 @@ bool ManifestParser::ParseEdge(string* err) {
329331
if (!CanonicalizePath(&path, &slash_bits, &path_err))
330332
return lexer_.Error(path_err, err);
331333
if (!state_->AddOut(edge, path, slash_bits)) {
332-
if (!quiet_) {
334+
if (dupe_edge_should_err_) {
335+
lexer_.Error("multiple rules generate " + path + " [-w dupbuild=err]",
336+
err);
337+
return false;
338+
} else if (!quiet_) {
333339
Warning("multiple rules generate %s. "
334340
"builds involving this target will not be correct; "
335-
"continuing anyway",
341+
"continuing anyway [-w dupbuild=warn]",
336342
path.c_str());
337343
}
338344
}

‎src/manifest_parser.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@ struct ManifestParser {
3232
virtual bool ReadFile(const string& path, string* content, string* err) = 0;
3333
};
3434

35-
ManifestParser(State* state, FileReader* file_reader);
35+
ManifestParser(State* state, FileReader* file_reader,
36+
bool dupe_edge_should_err = false);
3637

3738
/// Load and parse a file.
38-
bool Load(const string& filename, string* err, Lexer* parent=NULL);
39+
bool Load(const string& filename, string* err, Lexer* parent = NULL);
3940

4041
/// Parse a text string of input. Used by tests.
4142
bool ParseTest(const string& input, string* err) {
@@ -65,6 +66,7 @@ struct ManifestParser {
6566
BindingEnv* env_;
6667
FileReader* file_reader_;
6768
Lexer lexer_;
69+
bool dupe_edge_should_err_;
6870
bool quiet_;
6971
};
7072

‎src/manifest_parser_test.cc

+13
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,19 @@ TEST_F(ParserTest, NoDeadPointerFromDuplicateEdge) {
364364
// That's all the checking that this test needs.
365365
}
366366

367+
TEST_F(ParserTest, DuplicateEdgeWithMultipleOutputsError) {
368+
const char kInput[] =
369+
"rule cat\n"
370+
" command = cat $in > $out\n"
371+
"build out1 out2: cat in1\n"
372+
"build out1: cat in2\n"
373+
"build final: cat out1\n";
374+
ManifestParser parser(&state, this, /*dupe_edges_should_err=*/true);
375+
string err;
376+
EXPECT_FALSE(parser.ParseTest(kInput, &err));
377+
EXPECT_EQ("input:5: multiple rules generate out1 [-w dupbuild=err]\n", err);
378+
}
379+
367380
TEST_F(ParserTest, ReservedWords) {
368381
ASSERT_NO_FATAL_FAILURE(AssertParse(
369382
"rule build\n"

‎src/ninja.cc

+38-3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ struct Options {
6464

6565
/// Tool to run rather than building.
6666
const Tool* tool;
67+
68+
/// Whether duplicate rules for one target should warn or print an error.
69+
bool dupe_edges_should_err;
6770
};
6871

6972
/// The Ninja main() loads up a series of data structures; various tools need
@@ -199,7 +202,8 @@ void Usage(const BuildConfig& config) {
199202
"\n"
200203
" -d MODE enable debugging (use -d list to list modes)\n"
201204
" -t TOOL run a subtool (use -t list to list subtools)\n"
202-
" terminates toplevel options; further flags are passed to the tool\n",
205+
" terminates toplevel options; further flags are passed to the tool\n"
206+
" -w FLAG adjust warnings (use -w list to list warnings)\n",
203207
kNinjaVersion, config.parallelism);
204208
}
205209

@@ -792,6 +796,32 @@ bool DebugEnable(const string& name) {
792796
}
793797
}
794798

799+
/// Set a warning flag. Returns false if Ninja should exit instead of
800+
/// continuing.
801+
bool WarningEnable(const string& name, Options* options) {
802+
if (name == "list") {
803+
printf("warning flags:\n"
804+
" dupbuild={err,warn} multiple build lines for one target\n");
805+
return false;
806+
} else if (name == "dupbuild=err") {
807+
options->dupe_edges_should_err = true;
808+
return true;
809+
} else if (name == "dupbuild=warn") {
810+
options->dupe_edges_should_err = false;
811+
return true;
812+
} else {
813+
const char* suggestion =
814+
SpellcheckString(name.c_str(), "dupbuild=err", "dupbuild=warn", NULL);
815+
if (suggestion) {
816+
Error("unknown warning flag '%s', did you mean '%s'?",
817+
name.c_str(), suggestion);
818+
} else {
819+
Error("unknown warning flag '%s'", name.c_str());
820+
}
821+
return false;
822+
}
823+
}
824+
795825
bool NinjaMain::OpenBuildLog(bool recompact_only) {
796826
string log_path = ".ninja_log";
797827
if (!build_dir_.empty())
@@ -962,7 +992,7 @@ int ReadFlags(int* argc, char*** argv,
962992

963993
int opt;
964994
while (!options->tool &&
965-
(opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vC:h", kLongOptions,
995+
(opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vw:C:h", kLongOptions,
966996
NULL)) != -1) {
967997
switch (opt) {
968998
case 'd':
@@ -1011,6 +1041,10 @@ int ReadFlags(int* argc, char*** argv,
10111041
case 'v':
10121042
config->verbosity = BuildConfig::VERBOSE;
10131043
break;
1044+
case 'w':
1045+
if (!WarningEnable(optarg, options))
1046+
return 1;
1047+
break;
10141048
case 'C':
10151049
options->working_dir = optarg;
10161050
break;
@@ -1067,7 +1101,8 @@ int real_main(int argc, char** argv) {
10671101
NinjaMain ninja(ninja_command, config);
10681102

10691103
RealFileReader file_reader;
1070-
ManifestParser parser(&ninja.state_, &file_reader);
1104+
ManifestParser parser(&ninja.state_, &file_reader,
1105+
options.dupe_edges_should_err);
10711106
string err;
10721107
if (!parser.Load(options.input_file, &err)) {
10731108
Error("%s", err.c_str());

0 commit comments

Comments
 (0)
This repository has been archived.