r365975 - Re-land [JSONCompilationDatabase] Strip distcc/ccache/gomacc wrappers from parsed commands.
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 12 16:38:31 PDT 2019
Author: sammccall
Date: Fri Jul 12 16:38:31 2019
New Revision: 365975
URL: http://llvm.org/viewvc/llvm-project?rev=365975&view=rev
Log:
Re-land [JSONCompilationDatabase] Strip distcc/ccache/gomacc wrappers from parsed commands.
Use //net/dir like other test cases for windows compatibility
Modified:
cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp
cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp
Modified: cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp?rev=365975&r1=365974&r2=365975&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp (original)
+++ cfe/trunk/lib/Tooling/JSONCompilationDatabase.cpp Fri Jul 12 16:38:31 2019
@@ -256,15 +256,57 @@ JSONCompilationDatabase::getAllCompileCo
return Commands;
}
+static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
+ Name.consume_back(".exe");
+ return Name;
+}
+
+// There are compiler-wrappers (ccache, distcc, gomacc) that take the "real"
+// compiler as an argument, e.g. distcc gcc -O3 foo.c.
+// These end up in compile_commands.json when people set CC="distcc gcc".
+// Clang's driver doesn't understand this, so we need to unwrap.
+static bool unwrapCommand(std::vector<std::string> &Args) {
+ if (Args.size() < 2)
+ return false;
+ StringRef Wrapper =
+ stripExecutableExtension(llvm::sys::path::filename(Args.front()));
+ if (Wrapper == "distcc" || Wrapper == "gomacc" || Wrapper == "ccache") {
+ // Most of these wrappers support being invoked 3 ways:
+ // `distcc g++ file.c` This is the mode we're trying to match.
+ // We need to drop `distcc`.
+ // `distcc file.c` This acts like compiler is cc or similar.
+ // Clang's driver can handle this, no change needed.
+ // `g++ file.c` g++ is a symlink to distcc.
+ // We don't even notice this case, and all is well.
+ //
+ // We need to distinguish between the first and second case.
+ // The wrappers themselves don't take flags, so Args[1] is a compiler flag,
+ // an input file, or a compiler. Inputs have extensions, compilers don't.
+ bool HasCompiler =
+ (Args[1][0] != '-') &&
+ !llvm::sys::path::has_extension(stripExecutableExtension(Args[1]));
+ if (HasCompiler) {
+ Args.erase(Args.begin());
+ return true;
+ }
+ // If !HasCompiler, wrappers act like GCC. Fine: so do we.
+ }
+ return false;
+}
+
static std::vector<std::string>
nodeToCommandLine(JSONCommandLineSyntax Syntax,
const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
SmallString<1024> Storage;
- if (Nodes.size() == 1)
- return unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
std::vector<std::string> Arguments;
- for (const auto *Node : Nodes)
- Arguments.push_back(Node->getValue(Storage));
+ if (Nodes.size() == 1)
+ Arguments = unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
+ else
+ for (const auto *Node : Nodes)
+ Arguments.push_back(Node->getValue(Storage));
+ // There may be multiple wrappers: using distcc and ccache together is common.
+ while (unwrapCommand(Arguments))
+ ;
return Arguments;
}
Modified: cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp?rev=365975&r1=365974&r2=365975&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp (original)
+++ cfe/trunk/unittests/Tooling/CompilationDatabaseTest.cpp Fri Jul 12 16:38:31 2019
@@ -370,6 +370,33 @@ TEST(findCompileArgsInJsonDatabase, Find
EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
}
+TEST(findCompileArgsInJsonDatabase, ParsesCompilerWrappers) {
+ StringRef Directory("//net/dir");
+ StringRef FileName("//net/dir/filename");
+ std::vector<std::pair<std::string, std::string>> Cases = {
+ {"distcc gcc foo.c", "gcc foo.c"},
+ {"gomacc clang++ foo.c", "clang++ foo.c"},
+ {"ccache gcc foo.c", "gcc foo.c"},
+ {"ccache.exe gcc foo.c", "gcc foo.c"},
+ {"ccache g++.exe foo.c", "g++.exe foo.c"},
+ {"ccache distcc gcc foo.c", "gcc foo.c"},
+
+ {"distcc foo.c", "distcc foo.c"},
+ {"distcc -I/foo/bar foo.c", "distcc -I/foo/bar foo.c"},
+ };
+ std::string ErrorMessage;
+
+ for (const auto &Case : Cases) {
+ std::string DB =
+ R"([{"directory":"//net/dir", "file":"//net/dir/foo.c", "command":")" +
+ Case.first + "\"}]";
+ CompileCommand FoundCommand =
+ findCompileArgsInJsonDatabase("//net/dir/foo.c", DB, ErrorMessage);
+ EXPECT_EQ(Case.second, llvm::join(FoundCommand.CommandLine, " "))
+ << Case.first;
+ }
+}
+
static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
std::string JsonDatabase =
("[{\"directory\":\"//net/root\", \"file\":\"test\", \"command\": \"" +
More information about the cfe-commits
mailing list