summaryrefslogtreecommitdiffstats
path: root/src/depfile_parser.in.cc
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2018-11-21 18:31:22 (GMT)
committerGitHub <noreply@github.com>2018-11-21 18:31:22 (GMT)
commit0a2e2cae7038ce519b0524c07d7135c3e520c9cd (patch)
treeffe78231c4bdc8ad7e3a277a2b6b4f1822f5de0a /src/depfile_parser.in.cc
parent5a78423193c48cae4800eb1ec44b62d14ae03920 (diff)
parent8a9edb110354d5468ab42685cfece6a073146f27 (diff)
downloadNinja-0a2e2cae7038ce519b0524c07d7135c3e520c9cd.zip
Ninja-0a2e2cae7038ce519b0524c07d7135c3e520c9cd.tar.gz
Ninja-0a2e2cae7038ce519b0524c07d7135c3e520c9cd.tar.bz2
Merge pull request #1039 from bradking/improve-depfile-parser
Fix depfile parser handling of multiple rules
Diffstat (limited to 'src/depfile_parser.in.cc')
-rw-r--r--src/depfile_parser.in.cc72
1 files changed, 61 insertions, 11 deletions
diff --git a/src/depfile_parser.in.cc b/src/depfile_parser.in.cc
index 464efda..f8c94b3 100644
--- a/src/depfile_parser.in.cc
+++ b/src/depfile_parser.in.cc
@@ -13,6 +13,12 @@
// limitations under the License.
#include "depfile_parser.h"
+#include "util.h"
+
+DepfileParser::DepfileParser(DepfileParserOptions options)
+ : options_(options)
+{
+}
// A note on backslashes in Makefiles, from reading the docs:
// Backslash-newline is the line continuation character.
@@ -34,8 +40,13 @@ 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 have_newline_since_primary_target = false;
+ bool warned_distinct_target_lines = 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;
@@ -44,10 +55,12 @@ bool DepfileParser::Parse(string* content, string* err) {
for (;;) {
// start: beginning of the current parsed span.
const char* start = in;
+ char* yymarker = NULL;
/*!re2c
re2c:define:YYCTYPE = "unsigned char";
re2c:define:YYCURSOR = in;
re2c:define:YYLIMIT = end;
+ re2c:define:YYMARKER = yymarker;
re2c:yyfill:enable = 0;
@@ -56,6 +69,7 @@ bool DepfileParser::Parse(string* content, string* err) {
nul = "\000";
escape = [ \\#*[|\]];
+ newline = '\r'?'\n';
'\\' escape {
// De-escape backslashed character.
@@ -85,6 +99,15 @@ bool DepfileParser::Parse(string* content, string* err) {
nul {
break;
}
+ '\\' newline {
+ // A line continuation ends the current file name.
+ break;
+ }
+ newline {
+ // A newline ends the current file name and the current rule.
+ have_newline = true;
+ break;
+ }
[^] {
// For any other character (e.g. whitespace), swallow it here,
// allowing the outer logic to loop around again.
@@ -94,25 +117,52 @@ bool DepfileParser::Parse(string* content, string* err) {
}
int len = (int)(out - filename);
- const bool is_target = parsing_targets;
+ const bool is_dependency = !parsing_targets;
if (len > 0 && filename[len - 1] == ':') {
len--; // Strip off trailing colon, if any.
parsing_targets = false;
+ have_target = true;
}
- if (len == 0)
- continue;
+ if (len > 0) {
+ if (is_dependency) {
+ if (have_secondary_target_on_this_rule) {
+ if (!have_newline_since_primary_target) {
+ *err = "depfile has multiple output paths";
+ return false;
+ } else if (options_.depfile_distinct_target_lines_action_ ==
+ kDepfileDistinctTargetLinesActionError) {
+ *err =
+ "depfile has multiple output paths (on separate lines)"
+ " [-w depfilemulti=err]";
+ return false;
+ } else {
+ if (!warned_distinct_target_lines) {
+ warned_distinct_target_lines = true;
+ Warning("depfile has multiple output paths (on separate lines); "
+ "continuing anyway [-w depfilemulti=warn]");
+ }
+ continue;
+ }
+ }
+ ins_.push_back(StringPiece(filename, len));
+ } else if (!out_.str_) {
+ out_ = StringPiece(filename, len);
+ } else if (out_ != StringPiece(filename, len)) {
+ have_secondary_target_on_this_rule = true;
+ }
+ }
- if (!is_target) {
- 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;
+ 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 (have_target) {
+ have_newline_since_primary_target = true;
+ }
}
}
- if (parsing_targets) {
+ if (!have_target) {
*err = "expected ':' in depfile";
return false;
}