summaryrefslogtreecommitdiffstats
path: root/src/depfile_parser.in.cc
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2017-10-06 18:08:51 (GMT)
committerPeter Wu <peter@lekensteyn.nl>2019-06-08 05:49:52 (GMT)
commitfba5ce07367ce63ade61a560feed36ea9d315b0f (patch)
treef90b0347e6019f5b9adf06c7e9136e073b88df8b /src/depfile_parser.in.cc
parent28a7d1491367de7b39c854d166114f76d272f04f (diff)
downloadNinja-fba5ce07367ce63ade61a560feed36ea9d315b0f.zip
Ninja-fba5ce07367ce63ade61a560feed36ea9d315b0f.tar.gz
Ninja-fba5ce07367ce63ade61a560feed36ea9d315b0f.tar.bz2
Follow GCC/Clang behavior wrt depfiles
The option is called "depfile = gcc" and should support depfiles created by GCC. GCC does not escape backslashes and GNU Make does not try to unescape it, so neither should Ninja try to "unescape" it. Only space (' ') and hash sign ('#') are specially treated by GCC/Clang. Note that while tabs are also treated specially by GCC, Clang does not, so do not special case it (why would someone use tabs in a filename?). Support for 2N trailing backslashes in a filename is a bit questionable, but is added to be as consistent as possible with GCC/Clang. See also https://github.com/llvm-mirror/clang/blob/44c160f916a1b080098b17b466b026aa07475ec2/lib/Frontend/DependencyFile.cpp#L316 https://github.com/gcc-mirror/gcc/blob/22a8377023d59cc01ab0a84a1df56d0e1336efa3/libcpp/mkdeps.c#L47 Fixes https://github.com/ninja-build/ninja/issues/1262
Diffstat (limited to 'src/depfile_parser.in.cc')
-rw-r--r--src/depfile_parser.in.cc49
1 files changed, 35 insertions, 14 deletions
diff --git a/src/depfile_parser.in.cc b/src/depfile_parser.in.cc
index f8c94b3..735a0c3 100644
--- a/src/depfile_parser.in.cc
+++ b/src/depfile_parser.in.cc
@@ -29,9 +29,15 @@ DepfileParser::DepfileParser(DepfileParserOptions options)
// How do you end a line with a backslash? The netbsd Make docs suggest
// reading the result of a shell command echoing a backslash!
//
-// Rather than implement all of above, we do a simpler thing here:
-// Backslashes escape a set of characters (see "escapes" defined below),
-// otherwise they are passed through verbatim.
+// Rather than implement all of above, we follow what GCC/Clang produces:
+// Backslashes escape a space or hash sign.
+// When a space is preceded by 2N+1 backslashes, it is represents N backslashes
+// followed by space.
+// When a space is preceded by 2N backslashes, it represents 2N backslashes at
+// the end of a filename.
+// A hash sign is escaped by a single backslash. All other backslashes remain
+// unchanged.
+//
// If anyone actually has depfiles that rely on the more complicated
// behavior we can adjust this.
bool DepfileParser::Parse(string* content, string* err) {
@@ -68,12 +74,33 @@ bool DepfileParser::Parse(string* content, string* err) {
re2c:indent:string = " ";
nul = "\000";
- escape = [ \\#*[|\]];
newline = '\r'?'\n';
- '\\' escape {
- // De-escape backslashed character.
- *out++ = yych;
+ '\\\\'* '\\ ' {
+ // 2N+1 backslashes plus space -> N backslashes plus space.
+ int len = (int)(in - start);
+ int n = len / 2 - 1;
+ if (out < start)
+ memset(out, '\\', n);
+ out += n;
+ *out++ = ' ';
+ continue;
+ }
+ '\\\\'+ ' ' {
+ // 2N backslashes plus space -> 2N backslashes, end of filename.
+ int len = (int)(in - start);
+ if (out < start)
+ memset(out, '\\', len - 1);
+ out += len - 1;
+ break;
+ }
+ '\\'+ '#' {
+ // De-escape hash sign, but preserve other leading backslashes.
+ int len = (int)(in - start);
+ if (len > 2 && out < start)
+ memset(out, '\\', len - 2);
+ out += len - 2;
+ *out++ = '#';
continue;
}
'$$' {
@@ -81,13 +108,7 @@ bool DepfileParser::Parse(string* content, string* err) {
*out++ = '$';
continue;
}
- '\\' [^\000\r\n] {
- // Let backslash before other characters through verbatim.
- *out++ = '\\';
- *out++ = yych;
- continue;
- }
- [a-zA-Z0-9+,/_:.~()}{%@=!\x80-\xFF-]+ {
+ '\\'+ [^\000\r\n] | [a-zA-Z0-9+,/_:.~()}{%=@\x5B\x5D!\x80-\xFF-]+ {
// Got a span of plain text.
int len = (int)(in - start);
// Need to shift it over if we're overwriting backslashes.