#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
// C++ Includes
#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;
}
//===----------------------------------------------------------------------===//
#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;
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)));
+}