From: Kadir Cetinkaya Date: Wed, 26 Jun 2019 07:39:03 +0000 (+0000) Subject: [clang][Tooling] Infer target and mode from argv[0] when using JSONCompilationDatabase X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=617f68365c1fa6a86c64e03f86631fd1d8476ce3;p=clang [clang][Tooling] Infer target and mode from argv[0] when using JSONCompilationDatabase Summary: Wraps JSON compilation database with a target and mode adding database wrapper. So that driver can correctly figure out which toolchain to use. Note that clients that wants to make use of this target discovery mechanism needs to link in TargetsInfos and initialize them at startup. Reviewers: ilya-biryukov Subscribers: mgorny, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D63755 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364386 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/bindings/python/tests/cindex/test_cdb.py b/bindings/python/tests/cindex/test_cdb.py index e2a48f14cd..99bc72143b 100644 --- a/bindings/python/tests/cindex/test_cdb.py +++ b/bindings/python/tests/cindex/test_cdb.py @@ -63,15 +63,16 @@ class TestCDB(unittest.TestCase): expected = [ { 'wd': '/home/john.doe/MyProject', 'file': '/home/john.doe/MyProject/project.cpp', - 'line': ['clang++', '-o', 'project.o', '-c', + 'line': ['clang++', '--driver-mode=g++', '-o', 'project.o', '-c', '/home/john.doe/MyProject/project.cpp']}, { 'wd': '/home/john.doe/MyProjectA', 'file': '/home/john.doe/MyProject/project2.cpp', - 'line': ['clang++', '-o', 'project2.o', '-c', + 'line': ['clang++', '--driver-mode=g++', '-o', 'project2.o', '-c', '/home/john.doe/MyProject/project2.cpp']}, { 'wd': '/home/john.doe/MyProjectB', 'file': '/home/john.doe/MyProject/project2.cpp', - 'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c', + 'line': ['clang++', '--driver-mode=g++', '-DFEATURE=1', '-o', + 'project2-feature.o', '-c', '/home/john.doe/MyProject/project2.cpp']}, ] @@ -89,7 +90,7 @@ class TestCDB(unittest.TestCase): self.assertEqual(len(cmds), 1) self.assertEqual(cmds[0].directory, os.path.dirname(file)) self.assertEqual(cmds[0].filename, file) - expected = [ 'clang++', '-o', 'project.o', '-c', + expected = [ 'clang++', '--driver-mode=g++', '-o', 'project.o', '-c', '/home/john.doe/MyProject/project.cpp'] for arg, exp in zip(cmds[0].arguments, expected): self.assertEqual(arg, exp) @@ -101,10 +102,11 @@ class TestCDB(unittest.TestCase): self.assertEqual(len(cmds), 2) expected = [ { 'wd': '/home/john.doe/MyProjectA', - 'line': ['clang++', '-o', 'project2.o', '-c', + 'line': ['clang++', '--driver-mode=g++', '-o', 'project2.o', '-c', '/home/john.doe/MyProject/project2.cpp']}, { 'wd': '/home/john.doe/MyProjectB', - 'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c', + 'line': ['clang++', '--driver-mode=g++', '-DFEATURE=1', '-o', + 'project2-feature.o', '-c', '/home/john.doe/MyProject/project2.cpp']} ] for i in range(len(cmds)): diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h index 01f6e679a0..dea046a2dc 100644 --- a/include/clang/Tooling/CompilationDatabase.h +++ b/include/clang/Tooling/CompilationDatabase.h @@ -213,6 +213,12 @@ private: std::unique_ptr inferMissingCompileCommands(std::unique_ptr); +/// Returns a wrapped CompilationDatabase that will add -target and -mode flags +/// to commandline when they can be deduced from argv[0] of commandline returned +/// by underlying database. +std::unique_ptr +inferTargetAndDriverMode(std::unique_ptr Base); + } // namespace tooling } // namespace clang diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt index 6ed2f25acd..5a380fb8cc 100644 --- a/lib/Tooling/CMakeLists.txt +++ b/lib/Tooling/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangTooling Execution.cpp FileMatchTrie.cpp FixIt.cpp + GuessTargetAndModeCompilationDatabase.cpp InterpolatingCompilationDatabase.cpp JSONCompilationDatabase.cpp Refactoring.cpp diff --git a/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp b/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp new file mode 100644 index 0000000000..ac3faf1b01 --- /dev/null +++ b/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp @@ -0,0 +1,57 @@ +//===- GuessTargetAndModeCompilationDatabase.cpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Tooling.h" +#include + +namespace clang { +namespace tooling { + +namespace { +class TargetAndModeAdderDatabase : public CompilationDatabase { +public: + TargetAndModeAdderDatabase(std::unique_ptr Base) + : Base(std::move(Base)) { + assert(this->Base != nullptr); + } + + std::vector getAllFiles() const override { + return Base->getAllFiles(); + } + + std::vector getAllCompileCommands() const override { + return addTargetAndMode(Base->getAllCompileCommands()); + } + + std::vector + getCompileCommands(StringRef FilePath) const override { + return addTargetAndMode(Base->getCompileCommands(FilePath)); + } + +private: + std::vector + addTargetAndMode(std::vector Cmds) const { + for (auto &Cmd : Cmds) { + if (Cmd.CommandLine.empty()) + continue; + addTargetAndModeForProgramName(Cmd.CommandLine, Cmd.CommandLine.front()); + } + return Cmds; + } + std::unique_ptr Base; +}; +} // namespace + +std::unique_ptr +inferTargetAndDriverMode(std::unique_ptr Base) { + return llvm::make_unique(std::move(Base)); +} + +} // namespace tooling +} // namespace clang diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp index 0ee9d174b4..76a82b0fd9 100644 --- a/lib/Tooling/JSONCompilationDatabase.cpp +++ b/lib/Tooling/JSONCompilationDatabase.cpp @@ -14,7 +14,9 @@ #include "clang/Basic/LLVM.h" #include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/CompilationDatabasePluginRegistry.h" +#include "clang/Tooling/Tooling.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -165,7 +167,9 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin { llvm::sys::path::append(JSONDatabasePath, "compile_commands.json"); auto Base = JSONCompilationDatabase::loadFromFile( JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect); - return Base ? inferMissingCompileCommands(std::move(Base)) : nullptr; + return Base ? inferTargetAndDriverMode( + inferMissingCompileCommands(std::move(Base))) + : nullptr; } }; diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp index 19b797a0a6..d86c9bf79a 100644 --- a/unittests/Tooling/CompilationDatabaseTest.cpp +++ b/unittests/Tooling/CompilationDatabaseTest.cpp @@ -9,10 +9,12 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclGroup.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/FileMatchTrie.h" #include "clang/Tooling/JSONCompilationDatabase.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TargetSelect.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -632,7 +634,7 @@ struct MemCDB : public CompilationDatabase { } }; -class InterpolateTest : public ::testing::Test { +class MemDBTest : public ::testing::Test { protected: // Adds an entry to the underlying compilation database. // A flag is injected: -D , so the command used can be identified. @@ -658,6 +660,11 @@ protected: return Result.str(); } + MemCDB::EntryMap Entries; +}; + +class InterpolateTest : public MemDBTest { +protected: // Look up the command from a relative path, and return it in string form. // The input file is not included in the returned command. std::string getCommand(llvm::StringRef F) { @@ -693,8 +700,6 @@ protected: llvm::sys::path::native(Result, llvm::sys::path::Style::posix); return Result.str(); } - - MemCDB::EntryMap Entries; }; TEST_F(InterpolateTest, Nearby) { @@ -804,5 +809,30 @@ TEST(CompileCommandTest, EqualityOperator) { EXPECT_TRUE(CCRef != CCTest); } +class TargetAndModeTest : public MemDBTest { +public: + TargetAndModeTest() { llvm::InitializeAllTargetInfos(); } + +protected: + // Look up the command from a relative path, and return it in string form. + std::string getCommand(llvm::StringRef F) { + auto Results = inferTargetAndDriverMode(llvm::make_unique(Entries)) + ->getCompileCommands(path(F)); + if (Results.empty()) + return "none"; + return llvm::join(Results[0].CommandLine, " "); + } +}; + +TEST_F(TargetAndModeTest, TargetAndMode) { + add("foo.cpp", "clang-cl", ""); + add("bar.cpp", "x86_64-linux-clang", ""); + + EXPECT_EQ(getCommand("foo.cpp"), + "clang-cl --driver-mode=cl foo.cpp -D foo.cpp"); + EXPECT_EQ(getCommand("bar.cpp"), + "x86_64-linux-clang -target x86_64-linux bar.cpp -D bar.cpp"); +} + } // end namespace tooling } // end namespace clang