]> granicus.if.org Git - clang/commitdiff
Make clang-based tools find libc++ on MacOS
authorIlya Biryukov <ibiryukov@google.com>
Mon, 12 Nov 2018 13:55:55 +0000 (13:55 +0000)
committerIlya Biryukov <ibiryukov@google.com>
Mon, 12 Nov 2018 13:55:55 +0000 (13:55 +0000)
Summary:
When they read compiler args from compile_commands.json.
This change allows to run clang-based tools, like clang-tidy or clangd,
built from head using the compile_commands.json file produced for XCode
toolchains.

On MacOS clang can find the C++ standard library relative to the
compiler installation dir.

The logic to do this was based on resource dir as an approximation of
where the compiler is installed. This broke the tools that read
'compile_commands.json' and don't ship with the compiler, as they
typically change resource dir.

To workaround this, we now use compiler install dir detected by the driver
to better mimic the behavior of the original compiler when replaying the
compilations using other tools.

Reviewers: sammccall, arphaman, EricWF

Reviewed By: sammccall

Subscribers: ioeric, christof, kadircet, cfe-commits

Differential Revision: https://reviews.llvm.org/D54310

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@346652 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Lex/HeaderSearchOptions.h
lib/Frontend/CreateInvocationFromCommandLine.cpp
lib/Frontend/InitHeaderSearch.cpp
lib/Tooling/Tooling.cpp
test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector [new file with mode: 0644]
test/Tooling/clang-check-mac-libcxx-abspath.cpp [new file with mode: 0644]
test/Tooling/clang-check-mac-libcxx-relpath.cpp [new file with mode: 0644]

index e5b52b30323fa107403220c0e4c84bca2bda9344..bdf7b43f462013ff7282d0c59dc00357c849578a 100644 (file)
@@ -108,6 +108,13 @@ public:
   /// etc.).
   std::string ResourceDir;
 
+  /// Compiler install dir as detected by the Driver.
+  /// This is typically the directory that contains the clang executable, i.e.
+  /// the 'bin/' subdir of a clang distribution.
+  /// Only used to add include dirs for libc++ on Darwin. Please avoid relying
+  /// on this field for other purposes.
+  std::string InstallDir;
+
   /// The directory used for the module cache.
   std::string ModuleCachePath;
 
index 2d4c40f8b9f18411a60a01c8684d7742e26ae006..3a5e1e8b15ecb57460c3aac0842a26456d7720f6 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Frontend/Utils.h"
 #include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Driver/Action.h"
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/Driver.h"
-#include "clang/Driver/Action.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/Tool.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
 using namespace clang;
 using namespace llvm::opt;
 
@@ -102,5 +103,8 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
                                      CCArgs.size(),
                                      *Diags))
     return nullptr;
+  // Patch up the install dir, so we find the same standard library as the
+  // original compiler on MacOS.
+  CI->getHeaderSearchOpts().InstallDir = TheDriver.getInstalledDir();
   return CI;
 }
index deedb22f3e1cf87de73143c1c175070dc091027d..2f62ad3faf62295bd0321cb6cf8da5f2a4eb4bdd 100644 (file)
@@ -476,14 +476,9 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
       if (triple.isOSDarwin()) {
         // On Darwin, libc++ may be installed alongside the compiler in
         // include/c++/v1.
-        if (!HSOpts.ResourceDir.empty()) {
-          // Remove version from foo/lib/clang/version
-          StringRef NoVer = llvm::sys::path::parent_path(HSOpts.ResourceDir);
-          // Remove clang from foo/lib/clang
-          StringRef Lib = llvm::sys::path::parent_path(NoVer);
-          // Remove lib from foo/lib
-          SmallString<128> P = llvm::sys::path::parent_path(Lib);
-
+        if (!HSOpts.InstallDir.empty()) {
+          // Get from foo/bin to foo.
+          SmallString<128> P(llvm::sys::path::parent_path(HSOpts.InstallDir));
           // Get foo/include/c++/v1
           llvm::sys::path::append(P, "include", "c++", "v1");
           AddUnmappedPath(P, CXXSystem, false);
index cfdb32f0ae62feb62dacf2e92ff3cc115e59c6ea..f113e47cdc913abf3b10aa44c449732a4c8cc893 100644 (file)
@@ -327,6 +327,9 @@ bool ToolInvocation::run() {
     Invocation->getPreprocessorOpts().addRemappedFile(It.getKey(),
                                                       Input.release());
   }
+  // Patch up the install dir, so we find the same standard library as the
+  // original compiler on MacOS.
+  Invocation->getHeaderSearchOpts().InstallDir = Driver->getInstalledDir();
   return runInvocation(BinaryName, Compilation.get(), std::move(Invocation),
                        std::move(PCHContainerOps));
 }
diff --git a/test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector b/test/Tooling/Inputs/mock-libcxx/include/c++/v1/mock_vector
new file mode 100644 (file)
index 0000000..8512477
--- /dev/null
@@ -0,0 +1 @@
+class vector {};
diff --git a/test/Tooling/clang-check-mac-libcxx-abspath.cpp b/test/Tooling/clang-check-mac-libcxx-abspath.cpp
new file mode 100644 (file)
index 0000000..476ba3c
--- /dev/null
@@ -0,0 +1,17 @@
+// Clang on MacOS can find libc++ living beside the installed compiler.
+// This test makes sure our libTooling-based tools emulate this properly.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+//
+// Install the mock libc++ (simulates the libc++ directory structure).
+// RUN: cp -r %S/Inputs/mock-libcxx %t/
+//
+// Pretend clang is installed beside the mock library that we provided.
+// RUN: echo '[{"directory":"%t","command":"%t/mock-libcxx/bin/clang++ -stdlib=libc++ -target x86_64-apple-darwin -c test.cpp","file":"test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// RUN: cp "%s" "%t/test.cpp"
+// clang-check will produce an error code if the mock library is not found.
+// RUN: clang-check -p "%t" "%t/test.cpp"
+
+#include <mock_vector>
+vector v;
diff --git a/test/Tooling/clang-check-mac-libcxx-relpath.cpp b/test/Tooling/clang-check-mac-libcxx-relpath.cpp
new file mode 100644 (file)
index 0000000..099be5e
--- /dev/null
@@ -0,0 +1,17 @@
+// Clang on MacOS can find libc++ living beside the installed compiler.
+// This test makes sure our libTooling-based tools emulate this properly.
+//
+// RUN: rm -rf %t
+// RUN: mkdir %t
+//
+// Install the mock libc++ (simulates the libc++ directory structure).
+// RUN: cp -r %S/Inputs/mock-libcxx %t/
+//
+// Pretend clang is installed beside the mock library that we provided.
+// RUN: echo '[{"directory":"%t","command":"mock-libcxx/bin/clang++ -stdlib=libc++ -target x86_64-apple-darwin -c test.cpp","file":"test.cpp"}]' | sed -e 's/\\/\//g' > %t/compile_commands.json
+// RUN: cp "%s" "%t/test.cpp"
+// clang-check will produce an error code if the mock library is not found.
+// RUN: clang-check -p "%t" "%t/test.cpp"
+
+#include <mock_vector>
+vector v;