summaryrefslogtreecommitdiffstats
path: root/src/depfile_parser.cc
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2015-10-19 18:25:03 (GMT)
committerBrad King <brad.king@kitware.com>2018-11-19 15:23:45 (GMT)
commit4a4f9d40e178a9a9e88f4cd502d2be49bf7938d8 (patch)
treebdc9ce225fcac536bc17e3a77cc1f42d53eaf181 /src/depfile_parser.cc
parent6d6dfd17e83bbde57bee61a0956a73b12088a9d1 (diff)
downloadNinja-4a4f9d40e178a9a9e88f4cd502d2be49bf7938d8.zip
Ninja-4a4f9d40e178a9a9e88f4cd502d2be49bf7938d8.tar.gz
Ninja-4a4f9d40e178a9a9e88f4cd502d2be49bf7938d8.tar.bz2
Fix depfile parser handling of multiple rules
Currently we handle Makefile rules of the form: out: in1 in2 in3 and the form: out: in1 \ in2 \ in3 Teach the depfile parser to handle the additional form: out: in1 out: in2 out: in3 This is also valid Makefile syntax and is the depfile format generated by the Intel Compiler for Windows. Note that the `gcc -MP` option adds empty phony rules to the generated Makefile fragment: out: in1 in2 in3 in1: in2: in3: Previously we tolerated these because they were treated as inputs, which was accidentally correct. Instead we must now tolerate these by ignoring targets for which no dependencies are specified.
Diffstat (limited to 'src/depfile_parser.cc')
-rw-r--r--src/depfile_parser.cc104
1 files changed, 74 insertions, 30 deletions
diff --git a/src/depfile_parser.cc b/src/depfile_parser.cc
index 2ad2a00..7724eed 100644
--- a/src/depfile_parser.cc
+++ b/src/depfile_parser.cc
@@ -35,8 +35,11 @@ bool DepfileParser::Parse(string* content, string* err) {
// parsing_targets: whether we are parsing targets or dependencies.
char* in = &(*content)[0];
char* end = in + content->size();
+ bool have_target = false;
+ bool have_secondary_target_on_this_rule = false;
bool parsing_targets = true;
while (in < end) {
+ bool have_newline = false;
// out: current output point (typically same as in, but can fall behind
// as we de-escape backslashes).
char* out = in;
@@ -45,6 +48,7 @@ bool DepfileParser::Parse(string* content, string* err) {
for (;;) {
// start: beginning of the current parsed span.
const char* start = in;
+ char* yymarker = NULL;
{
unsigned char yych;
@@ -84,17 +88,25 @@ bool DepfileParser::Parse(string* content, string* err) {
};
yych = *in;
if (yybm[0+yych] & 128) {
- goto yy6;
- }
- if (yych <= '$') {
- if (yych <= 0x00) goto yy2;
- if (yych <= '#') goto yy4;
goto yy9;
+ }
+ if (yych <= '\r') {
+ if (yych <= '\t') {
+ if (yych >= 0x01) goto yy4;
+ } else {
+ if (yych <= '\n') goto yy6;
+ if (yych <= '\f') goto yy4;
+ goto yy8;
+ }
} else {
- if (yych == '\\') goto yy10;
- goto yy4;
+ if (yych <= '$') {
+ if (yych <= '#') goto yy4;
+ goto yy12;
+ } else {
+ if (yych == '\\') goto yy13;
+ goto yy4;
+ }
}
-yy2:
++in;
{
break;
@@ -108,9 +120,20 @@ yy5:
break;
}
yy6:
+ ++in;
+ {
+ // A newline ends the current file name and the current rule.
+ have_newline = true;
+ break;
+ }
+yy8:
+ yych = *++in;
+ if (yych == '\n') goto yy6;
+ goto yy5;
+yy9:
yych = *++in;
if (yybm[0+yych] & 128) {
- goto yy6;
+ goto yy9;
}
{
// Got a span of plain text.
@@ -121,41 +144,41 @@ yy6:
out += len;
continue;
}
-yy9:
+yy12:
yych = *++in;
- if (yych == '$') goto yy11;
+ if (yych == '$') goto yy14;
goto yy5;
-yy10:
- yych = *++in;
+yy13:
+ yych = *(yymarker = ++in);
if (yych <= '"') {
if (yych <= '\f') {
if (yych <= 0x00) goto yy5;
- if (yych == '\n') goto yy5;
- goto yy13;
+ if (yych == '\n') goto yy18;
+ goto yy16;
} else {
- if (yych <= '\r') goto yy5;
- if (yych == ' ') goto yy15;
- goto yy13;
+ if (yych <= '\r') goto yy20;
+ if (yych == ' ') goto yy22;
+ goto yy16;
}
} else {
if (yych <= 'Z') {
- if (yych <= '#') goto yy15;
- if (yych == '*') goto yy15;
- goto yy13;
+ if (yych <= '#') goto yy22;
+ if (yych == '*') goto yy22;
+ goto yy16;
} else {
- if (yych <= ']') goto yy15;
- if (yych == '|') goto yy15;
- goto yy13;
+ if (yych <= ']') goto yy22;
+ if (yych == '|') goto yy22;
+ goto yy16;
}
}
-yy11:
+yy14:
++in;
{
// De-escape dollar character.
*out++ = '$';
continue;
}
-yy13:
+yy16:
++in;
{
// Let backslash before other characters through verbatim.
@@ -163,7 +186,18 @@ yy13:
*out++ = yych;
continue;
}
-yy15:
+yy18:
+ ++in;
+ {
+ // A line continuation ends the current file name.
+ break;
+ }
+yy20:
+ yych = *++in;
+ if (yych == '\n') goto yy18;
+ in = yymarker;
+ goto yy5;
+yy22:
++in;
{
// De-escape backslashed character.
@@ -179,20 +213,30 @@ yy15:
if (len > 0 && filename[len - 1] == ':') {
len--; // Strip off trailing colon, if any.
parsing_targets = false;
+ have_target = true;
}
if (len > 0) {
if (is_dependency) {
+ if (have_secondary_target_on_this_rule) {
+ *err = "depfile has multiple output paths";
+ return false;
+ }
ins_.push_back(StringPiece(filename, len));
} else if (!out_.str_) {
out_ = StringPiece(filename, len);
} else if (out_ != StringPiece(filename, len)) {
- *err = "depfile has multiple output paths";
- return false;
+ have_secondary_target_on_this_rule = true;
}
}
+
+ if (have_newline) {
+ // A newline ends a rule so the next filename will be a new target.
+ parsing_targets = true;
+ have_secondary_target_on_this_rule = false;
+ }
}
- if (parsing_targets) {
+ if (!have_target) {
*err = "expected ':' in depfile";
return false;
}