From 037b0934f929ba17434906fb781aeb1acb583385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20K=C3=BCmmel?= Date: Sun, 13 Oct 2013 12:20:17 +0200 Subject: add deps_prefix for localized /showIncludes' output parsing --- doc/manual.asciidoc | 10 +++++++++- src/build.cc | 6 ++++-- src/build.h | 2 +- src/includes_normalize_test.cc | 2 +- src/msvc_helper-win32.cc | 15 +++++++-------- src/msvc_helper.h | 4 ++-- src/msvc_helper_main-win32.cc | 9 +++++++-- src/msvc_helper_test.cc | 29 +++++++++++++++++++---------- 8 files changed, 50 insertions(+), 27 deletions(-) diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc index a735257..67fcbfd 100644 --- a/doc/manual.asciidoc +++ b/doc/manual.asciidoc @@ -580,9 +580,13 @@ Ninja supports this processing in two forms. http://msdn.microsoft.com/en-us/library/hdkef6tk(v=vs.90).aspx[`/showIncludes` flag]. Briefly, this means the tool outputs specially-formatted lines to its stdout. Ninja then filters these lines from the displayed - output. No `depfile` attribute is necessary. + output. No `depfile` attribute is necessary, but the localized string + in front of the the header file path. For instance + `msvc_deps_prefix = Note: including file: ` + for a English Visual Studio (the default). Should be globally defined. + ---- +msvc_deps_prefix = Note: including file: rule cc deps = msvc command = cl /showIncludes -c $in /Fo$out @@ -772,6 +776,10 @@ keys. stored as `.ninja_deps` in the `builddir`, see <>. +`msvc_deps_prefix`:: _(Available since Ninja 1.5.)_ defines the string + which should be stripped from msvc's /showIncludes output. Only + needed when `deps = msvc` and no English Visual Studio version is used. + `description`:: a short description of the command, used to pretty-print the command as it's running. The `-v` flag controls whether to print the full command or its description; if a command fails, the full command diff --git a/src/build.cc b/src/build.cc index 9718f85..33aa85b 100644 --- a/src/build.cc +++ b/src/build.cc @@ -714,9 +714,10 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) { // build perspective. vector deps_nodes; string deps_type = edge->GetBinding("deps"); + const string deps_prefix = edge->GetBinding("msvc_deps_prefix"); if (!deps_type.empty()) { string extract_err; - if (!ExtractDeps(result, deps_type, &deps_nodes, &extract_err) && + if (!ExtractDeps(result, deps_type, deps_prefix, &deps_nodes, &extract_err) && result->success()) { if (!result->output.empty()) result->output.append("\n"); @@ -802,12 +803,13 @@ bool Builder::FinishCommand(CommandRunner::Result* result, string* err) { bool Builder::ExtractDeps(CommandRunner::Result* result, const string& deps_type, + const string& deps_prefix, vector* deps_nodes, string* err) { #ifdef _WIN32 if (deps_type == "msvc") { CLParser parser; - result->output = parser.Parse(result->output); + result->output = parser.Parse(result->output, deps_prefix); for (set::iterator i = parser.includes_.begin(); i != parser.includes_.end(); ++i) { deps_nodes->push_back(state_->GetNode(*i)); diff --git a/src/build.h b/src/build.h index 5b6c83c..1122d84 100644 --- a/src/build.h +++ b/src/build.h @@ -180,7 +180,7 @@ struct Builder { BuildStatus* status_; private: - bool ExtractDeps(CommandRunner::Result* result, const string& deps_type, + bool ExtractDeps(CommandRunner::Result* result, const string& deps_type, const string& deps_prefix, vector* deps_nodes, string* err); DiskInterface* disk_interface_; diff --git a/src/includes_normalize_test.cc b/src/includes_normalize_test.cc index 1713d5d..419996f 100644 --- a/src/includes_normalize_test.cc +++ b/src/includes_normalize_test.cc @@ -38,7 +38,7 @@ string GetCurDir() { } // namespace TEST(IncludesNormalize, WithRelative) { - string currentdir = IncludesNormalize::ToLower(GetCurDir()); + string currentdir = GetCurDir(); EXPECT_EQ("c", IncludesNormalize::Normalize("a/b/c", "a/b")); EXPECT_EQ("a", IncludesNormalize::Normalize(IncludesNormalize::AbsPath("a"), NULL)); diff --git a/src/msvc_helper-win32.cc b/src/msvc_helper-win32.cc index 7c45029..3065ab0 100644 --- a/src/msvc_helper-win32.cc +++ b/src/msvc_helper-win32.cc @@ -48,14 +48,13 @@ string EscapeForDepfile(const string& path) { } // static -string CLParser::FilterShowIncludes(const string& line) { - static const char kMagicPrefix[] = "Note: including file: "; +string CLParser::FilterShowIncludes(const string& line, const string& deps_prefix) { + static const string deps_prefix_english = "Note: including file: "; const char* in = line.c_str(); const char* end = in + line.size(); - - if (end - in > (int)sizeof(kMagicPrefix) - 1 && - memcmp(in, kMagicPrefix, sizeof(kMagicPrefix) - 1) == 0) { - in += sizeof(kMagicPrefix) - 1; + const string& prefix = deps_prefix.empty() ? deps_prefix_english : deps_prefix; + if (end - in > (int)prefix.size() && memcmp(in, prefix.c_str(), (int)prefix.size()) == 0) { + in += prefix.size(); while (*in == ' ') ++in; return line.substr(in - line.c_str()); @@ -81,7 +80,7 @@ bool CLParser::FilterInputFilename(string line) { EndsWith(line, ".cpp"); } -string CLParser::Parse(const string& output) { +string CLParser::Parse(const string& output, const string& deps_prefix) { string filtered_output; // Loop over all lines in the output to process them. @@ -92,7 +91,7 @@ string CLParser::Parse(const string& output) { end = output.size(); string line = output.substr(start, end - start); - string include = FilterShowIncludes(line); + string include = FilterShowIncludes(line, deps_prefix); if (!include.empty()) { include = IncludesNormalize::Normalize(include, NULL); if (!IsSystemInclude(include)) diff --git a/src/msvc_helper.h b/src/msvc_helper.h index e207485..0433769 100644 --- a/src/msvc_helper.h +++ b/src/msvc_helper.h @@ -27,7 +27,7 @@ struct CLParser { /// Parse a line of cl.exe output and extract /showIncludes info. /// If a dependency is extracted, returns a nonempty string. /// Exposed for testing. - static string FilterShowIncludes(const string& line); + static string FilterShowIncludes(const string& line, const string& deps_prefix); /// Return true if a mentioned include file is a system path. /// Filtering these out reduces dependency information considerably. @@ -41,7 +41,7 @@ struct CLParser { /// Parse the full output of cl, returning the output (if any) that /// should printed. - string Parse(const string& output); + string Parse(const string& output, const string& deps_prefix); set includes_; }; diff --git a/src/msvc_helper_main-win32.cc b/src/msvc_helper_main-win32.cc index e3a7846..58bc797 100644 --- a/src/msvc_helper_main-win32.cc +++ b/src/msvc_helper_main-win32.cc @@ -31,6 +31,7 @@ void Usage() { "options:\n" " -e ENVFILE load environment block from ENVFILE as environment\n" " -o FILE write output dependency information to FILE.d\n" +" -p STRING localized prefix of msvc's /showIncludes output\n" ); } @@ -84,7 +85,8 @@ int MSVCHelperMain(int argc, char** argv) { { NULL, 0, NULL, 0 } }; int opt; - while ((opt = getopt_long(argc, argv, "e:o:h", kLongOptions, NULL)) != -1) { + string deps_prefix; + while ((opt = getopt_long(argc, argv, "e:o:p:h", kLongOptions, NULL)) != -1) { switch (opt) { case 'e': envfile = optarg; @@ -92,6 +94,9 @@ int MSVCHelperMain(int argc, char** argv) { case 'o': output_filename = optarg; break; + case 'p': + deps_prefix = optarg; + break; case 'h': default: Usage(); @@ -122,7 +127,7 @@ int MSVCHelperMain(int argc, char** argv) { if (output_filename) { CLParser parser; - output = parser.Parse(output); + output = parser.Parse(output, deps_prefix); WriteDepFileOrDie(output_filename, parser); } diff --git a/src/msvc_helper_test.cc b/src/msvc_helper_test.cc index 02f2863..48fbe21 100644 --- a/src/msvc_helper_test.cc +++ b/src/msvc_helper_test.cc @@ -20,15 +20,19 @@ #include "util.h" TEST(CLParserTest, ShowIncludes) { - ASSERT_EQ("", CLParser::FilterShowIncludes("")); + ASSERT_EQ("", CLParser::FilterShowIncludes("", "")); - ASSERT_EQ("", CLParser::FilterShowIncludes("Sample compiler output")); + ASSERT_EQ("", CLParser::FilterShowIncludes("Sample compiler output", "")); ASSERT_EQ("c:\\Some Files\\foobar.h", CLParser::FilterShowIncludes("Note: including file: " - "c:\\Some Files\\foobar.h")); + "c:\\Some Files\\foobar.h", "")); ASSERT_EQ("c:\\initspaces.h", CLParser::FilterShowIncludes("Note: including file: " - "c:\\initspaces.h")); + "c:\\initspaces.h", "")); + ASSERT_EQ("c:\\initspaces.h", + CLParser::FilterShowIncludes("Non-default prefix: inc file: " + "c:\\initspaces.h", + "Non-default prefix: inc file:")); } TEST(CLParserTest, FilterInputFilename) { @@ -46,8 +50,9 @@ TEST(CLParserTest, ParseSimple) { CLParser parser; string output = parser.Parse( "foo\r\n" - "Note: including file: foo.h\r\n" - "bar\r\n"); + "Note: inc file prefix: foo.h\r\n" + "bar\r\n", + "Note: inc file prefix:"); ASSERT_EQ("foo\nbar\n", output); ASSERT_EQ(1u, parser.includes_.size()); @@ -58,7 +63,8 @@ TEST(CLParserTest, ParseFilenameFilter) { CLParser parser; string output = parser.Parse( "foo.cc\r\n" - "cl: warning\r\n"); + "cl: warning\r\n", + ""); ASSERT_EQ("cl: warning\n", output); } @@ -67,7 +73,8 @@ TEST(CLParserTest, ParseSystemInclude) { string output = parser.Parse( "Note: including file: c:\\Program Files\\foo.h\r\n" "Note: including file: d:\\Microsoft Visual Studio\\bar.h\r\n" - "Note: including file: path.h\r\n"); + "Note: including file: path.h\r\n", + ""); // We should have dropped the first two includes because they look like // system headers. ASSERT_EQ("", output); @@ -80,7 +87,8 @@ TEST(CLParserTest, DuplicatedHeader) { string output = parser.Parse( "Note: including file: foo.h\r\n" "Note: including file: bar.h\r\n" - "Note: including file: foo.h\r\n"); + "Note: including file: foo.h\r\n", + ""); // We should have dropped one copy of foo.h. ASSERT_EQ("", output); ASSERT_EQ(2u, parser.includes_.size()); @@ -91,7 +99,8 @@ TEST(CLParserTest, DuplicatedHeaderPathConverted) { string output = parser.Parse( "Note: including file: sub/foo.h\r\n" "Note: including file: bar.h\r\n" - "Note: including file: sub\\foo.h\r\n"); + "Note: including file: sub\\foo.h\r\n", + ""); // We should have dropped one copy of foo.h. ASSERT_EQ("", output); ASSERT_EQ(2u, parser.includes_.size()); -- cgit v0.12