diff options
author | Sam McCall <sam.mccall@gmail.com> | 2019-07-12 10:11:40 +0000 |
---|---|---|
committer | Sam McCall <sam.mccall@gmail.com> | 2019-07-12 10:11:40 +0000 |
commit | 9c0391b36a76f8e3949588de3f44b7314c2318bf (patch) | |
tree | eaa0ffe78c36dbc9d381a1eada7ff253a2b18d7b /clang/lib/Tooling/JSONCompilationDatabase.cpp | |
parent | 0739ccd3b588a6f2562bdc5a8f8847a49356394e (diff) | |
download | bcm5719-llvm-9c0391b36a76f8e3949588de3f44b7314c2318bf.tar.gz bcm5719-llvm-9c0391b36a76f8e3949588de3f44b7314c2318bf.zip |
[JSONCompilationDatabase] Strip distcc/ccache/gomacc wrappers from parsed commands.
Summary:
It's common to use compiler wrappers by setting CC="gomacc clang++".
This results in both args appearing in compile_commands.json, and clang's driver
can't handle this.
This patch attempts to recognize this pattern (by looking for well-known
wrappers) and dropping argv0 in this case.
It conservatively ignores other cases for now:
- wrappers with unknown names
- wrappers that accept -flags
- wrappers where the compiler to use is implied (usually cc or gcc)
This is done at the JSONCompilationDatabase level rather than somewhere more
fundamental, as (hopefully) this isn't a general conceptual problem, but a messy
aspect of the nature of the ecosystem around compile_commands.json.
i.e. compilation databases more tightly tied to the build system should not have
this problem.
Reviewers: phosek, klimek
Subscribers: llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D64297
llvm-svn: 365887
Diffstat (limited to 'clang/lib/Tooling/JSONCompilationDatabase.cpp')
-rw-r--r-- | clang/lib/Tooling/JSONCompilationDatabase.cpp | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp index 76a82b0fd9b..f19a0f7550b 100644 --- a/clang/lib/Tooling/JSONCompilationDatabase.cpp +++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp @@ -256,15 +256,57 @@ JSONCompilationDatabase::getAllCompileCommands() const { 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; } |