HostInfoMacOSX: Share the clang resource directory with Swift.
authorAdrian Prantl <aprantl@apple.com>
Fri, 11 May 2018 17:54:09 +0000 (17:54 +0000)
committerAdrian Prantl <aprantl@apple.com>
Fri, 11 May 2018 17:54:09 +0000 (17:54 +0000)
Inside Xcode and in Xcode toolchains LLDB is always in lockstep
with the Swift compiler, so it can reuse its Clang resource
directory. This allows LLDB and the Swift compiler to share the
same Clang module cache.

rdar://problem/40039633

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

llvm-svn: 332111

lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
lldb/source/Host/macosx/HostInfoMacOSX.mm
lldb/unittests/Host/CMakeLists.txt
lldb/unittests/Host/HostInfoTest.cpp

index eee842b..26437d3 100644 (file)
@@ -38,6 +38,8 @@ protected:
   static bool ComputeHeaderDirectory(FileSpec &file_spec);
   static bool ComputePythonDirectory(FileSpec &file_spec);
   static bool ComputeClangDirectory(FileSpec &file_spec);
+  static bool ComputeClangDirectory(FileSpec &lldb_shlib_spec,
+                                    FileSpec &file_spec, bool verify);
   static bool ComputeSystemPluginsDirectory(FileSpec &file_spec);
   static bool ComputeUserPluginsDirectory(FileSpec &file_spec);
 };
index bacf6fa..1611826 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 
 // C++ Includes
@@ -226,21 +227,67 @@ bool HostInfoMacOSX::ComputePythonDirectory(FileSpec &file_spec) {
 #endif
 }
 
+static bool VerifyClangPath(const llvm::Twine &clang_path) {
+  if (llvm::sys::fs::is_directory(clang_path))
+    return true;
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+  if (log)
+    log->Printf("HostInfoMacOSX::ComputeClangDirectory(): "
+                "failed to stat clang resource directory at \"%s\"",
+                clang_path.str().c_str());
+  return false;
+}
+
 bool HostInfoMacOSX::ComputeClangDirectory(FileSpec &file_spec) {
   FileSpec lldb_file_spec;
   if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
     return false;
+  return ComputeClangDirectory(lldb_file_spec, file_spec, true);
+}
 
-  std::string raw_path = lldb_file_spec.GetPath();
+bool HostInfoMacOSX::ComputeClangDirectory(FileSpec &lldb_shlib_spec,
+                                           FileSpec &file_spec, bool verify) {
+  std::string raw_path = lldb_shlib_spec.GetPath();
 
-  size_t framework_pos = raw_path.find("LLDB.framework");
-  if (framework_pos == std::string::npos)
+  auto rev_it = llvm::sys::path::rbegin(raw_path);
+  auto r_end = llvm::sys::path::rend(raw_path);
+
+  // Check for a Posix-style build of LLDB.
+  if (rev_it == r_end || *rev_it != "LLDB.framework")
     return HostInfoPosix::ComputeClangDirectory(file_spec);
-  
-  framework_pos += strlen("LLDB.framework");
-  raw_path.resize(framework_pos);
+
+  // Inside Xcode and in Xcode toolchains LLDB is always in lockstep
+  // with the Swift compiler, so it can reuse its Clang resource
+  // directory. This allows LLDB and the Swift compiler to share the
+  // same Clang module cache.
+  llvm::SmallString<256> clang_path;
+  const char *swift_clang_resource_dir = "usr/lib/swift/clang";
+  ++rev_it;
+  if (rev_it != r_end && *rev_it == "SharedFrameworks") {
+    // This is the top-level LLDB in the Xcode.app bundle.
+    raw_path.resize(rev_it - r_end);
+    llvm::sys::path::append(clang_path, raw_path,
+                            "Developer/Toolchains/XcodeDefault.xctoolchain",
+                            swift_clang_resource_dir);
+    if (!verify || VerifyClangPath(clang_path)) {
+      file_spec.SetFile(clang_path.c_str(), true);
+      return true;
+    }
+  } else if (rev_it != r_end && *rev_it == "PrivateFrameworks" &&
+             ++rev_it != r_end && ++rev_it != r_end) {
+    // This is LLDB inside an Xcode toolchain.
+    raw_path.resize(rev_it - r_end);
+    llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir);
+    if (!verify || VerifyClangPath(clang_path)) {
+      file_spec.SetFile(clang_path.c_str(), true);
+      return true;
+    }
+  } else {
+    raw_path.resize(rev_it - r_end);
+  }
+
+  // Fall back to the Clang resource directory inside the framework.
   raw_path.append("/Resources/Clang");
-  
   file_spec.SetFile(raw_path.c_str(), true);
   return true;
 }
index 939e5d2..f176853 100644 (file)
@@ -22,4 +22,5 @@ add_lldb_unittest(HostTests
   LINK_LIBS
     lldbCore
     lldbHost
+    lldbUtilityHelpers
   )
index 75b8c77..4205ce3 100644 (file)
@@ -8,7 +8,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Host/HostInfo.h"
+#include "lldb/Host/macosx/HostInfoMacOSX.h"
 #include "lldb/lldb-defines.h"
+#include "TestingSupport/TestUtilities.h"
 #include "gtest/gtest.h"
 
 using namespace lldb_private;
@@ -43,3 +45,41 @@ TEST_F(HostInfoTest, GetAugmentedArchSpec) {
   EXPECT_EQ(HostInfo::GetAugmentedArchSpec(LLDB_ARCH_DEFAULT).GetTriple(),
             HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple());
 }
+
+
+struct HostInfoMacOSXTest : public HostInfoMacOSX {
+  static std::string ComputeClangDir(std::string lldb_shlib_path,
+                                     bool verify = false) {
+    FileSpec clang_dir;
+    FileSpec lldb_shlib_spec(lldb_shlib_path, false);
+    ComputeClangDirectory(lldb_shlib_spec, clang_dir, verify);
+    return clang_dir.GetPath();
+  }
+};
+
+
+TEST_F(HostInfoTest, MacOSX) {
+  // This returns whatever the POSIX fallback returns.
+  std::string posix = "/usr/lib/liblldb.dylib";
+  EXPECT_FALSE(HostInfoMacOSXTest::ComputeClangDir(posix).empty());
+
+  std::string xcode =
+    "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework";
+  std::string xcode_clang =
+    "/Applications/Xcode.app/Contents/Developer/Toolchains/"
+    "XcodeDefault.xctoolchain/usr/lib/swift/clang";
+  EXPECT_EQ(HostInfoMacOSXTest::ComputeClangDir(xcode), xcode_clang);
+
+  std::string toolchain =
+      "/Applications/Xcode.app/Contents/Developer/Toolchains/"
+      "Swift-4.1-development-snapshot.xctoolchain/System/Library/"
+      "PrivateFrameworks/LLDB.framework";
+  std::string toolchain_clang =
+      "/Applications/Xcode.app/Contents/Developer/Toolchains/"
+      "Swift-4.1-development-snapshot.xctoolchain/usr/lib/swift/clang";
+  EXPECT_EQ(HostInfoMacOSXTest::ComputeClangDir(toolchain), toolchain_clang);
+
+  // Test that a bogus path is detected.
+  EXPECT_NE(HostInfoMacOSXTest::ComputeClangDir(GetInputFilePath(xcode), true),
+            HostInfoMacOSXTest::ComputeClangDir(GetInputFilePath(xcode)));
+}