Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
39648 views
//===-- ClangHost.cpp -----------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ClangHost.h"910#include "clang/Basic/Version.h"11#include "clang/Config/config.h"12#include "clang/Driver/Driver.h"1314#include "llvm/ADT/StringRef.h"15#include "llvm/ADT/Twine.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/Threading.h"1819#include "lldb/Host/Config.h"20#include "lldb/Host/FileSystem.h"21#include "lldb/Host/HostInfo.h"22#include "lldb/Utility/FileSpec.h"23#include "lldb/Utility/LLDBLog.h"24#include "lldb/Utility/Log.h"2526#include <string>2728using namespace lldb_private;2930static bool VerifyClangPath(const llvm::Twine &clang_path) {31if (FileSystem::Instance().IsDirectory(clang_path))32return true;33Log *log = GetLog(LLDBLog::Host);34LLDB_LOGF(log,35"VerifyClangPath(): "36"failed to stat clang resource directory at \"%s\"",37clang_path.str().c_str());38return false;39}4041///42/// This will compute the clang resource directory assuming that clang was43/// installed with the same prefix as lldb.44///45/// If verify is true, the first candidate resource directory will be returned.46/// This mode is only used for testing.47///48static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,49FileSpec &file_spec,50bool verify) {51Log *log = GetLog(LLDBLog::Host);52std::string raw_path = lldb_shlib_spec.GetPath();53llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);54static const std::string clang_resource_path =55clang::driver::Driver::GetResourcesPath("bin/lldb", CLANG_RESOURCE_DIR);5657static const llvm::StringRef kResourceDirSuffixes[] = {58// LLVM.org's build of LLDB uses the clang resource directory placed59// in $install_dir/lib{,64}/clang/$clang_version or60// $install_dir/bin/$CLANG_RESOURCE_DIR61clang_resource_path,62// swift-lldb uses the clang resource directory copied from swift, which63// by default is placed in $install_dir/lib{,64}/lldb/clang. LLDB places64// it there, so we use LLDB_INSTALL_LIBDIR_BASENAME.65LLDB_INSTALL_LIBDIR_BASENAME "/lldb/clang",66};6768for (const auto &Suffix : kResourceDirSuffixes) {69llvm::SmallString<256> clang_dir(parent_dir);70llvm::SmallString<32> relative_path(Suffix);71llvm::sys::path::native(relative_path);72llvm::sys::path::append(clang_dir, relative_path);73if (!verify || VerifyClangPath(clang_dir)) {74LLDB_LOG(log,75"DefaultComputeClangResourceDir: Setting ClangResourceDir "76"to \"{0}\", verify = {1}",77clang_dir.str(), verify ? "true" : "false");78file_spec.SetDirectory(clang_dir);79FileSystem::Instance().Resolve(file_spec);80return true;81}82}8384return false;85}8687bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,88FileSpec &file_spec,89bool verify) {90#if !defined(__APPLE__)91return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,92verify);93#else94std::string raw_path = lldb_shlib_spec.GetPath();9596auto rev_it = llvm::sys::path::rbegin(raw_path);97auto r_end = llvm::sys::path::rend(raw_path);9899// Check for a Posix-style build of LLDB.100while (rev_it != r_end) {101if (*rev_it == "LLDB.framework")102break;103++rev_it;104}105106// We found a non-framework build of LLDB107if (rev_it == r_end)108return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,109verify);110111// Inside Xcode and in Xcode toolchains LLDB is always in lockstep112// with the Swift compiler, so it can reuse its Clang resource113// directory. This allows LLDB and the Swift compiler to share the114// same Clang module cache.115llvm::SmallString<256> clang_path;116const char *swift_clang_resource_dir = "usr/lib/swift/clang";117auto parent = std::next(rev_it);118if (parent != r_end && *parent == "SharedFrameworks") {119// This is the top-level LLDB in the Xcode.app bundle.120// E.g., "Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A"121raw_path.resize(parent - r_end);122llvm::sys::path::append(clang_path, raw_path,123"Developer/Toolchains/XcodeDefault.xctoolchain",124swift_clang_resource_dir);125if (!verify || VerifyClangPath(clang_path)) {126file_spec.SetDirectory(clang_path);127FileSystem::Instance().Resolve(file_spec);128return true;129}130} else if (parent != r_end && *parent == "PrivateFrameworks" &&131std::distance(parent, r_end) > 2) {132++parent;133++parent;134if (*parent == "System") {135// This is LLDB inside an Xcode toolchain.136// E.g., "Xcode.app/Contents/Developer/Toolchains/" \137// "My.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework"138raw_path.resize(parent - r_end);139llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir);140if (!verify || VerifyClangPath(clang_path)) {141file_spec.SetDirectory(clang_path);142FileSystem::Instance().Resolve(file_spec);143return true;144}145}146}147148// Fall back to the Clang resource directory inside the framework.149raw_path = lldb_shlib_spec.GetPath();150raw_path.resize(rev_it - r_end);151raw_path.append("LLDB.framework/Resources/Clang");152file_spec.SetDirectory(raw_path);153FileSystem::Instance().Resolve(file_spec);154return true;155#endif // __APPLE__156}157158FileSpec lldb_private::GetClangResourceDir() {159static FileSpec g_cached_resource_dir;160static llvm::once_flag g_once_flag;161llvm::call_once(g_once_flag, []() {162if (FileSpec lldb_file_spec = HostInfo::GetShlibDir())163ComputeClangResourceDirectory(lldb_file_spec, g_cached_resource_dir,164true);165Log *log = GetLog(LLDBLog::Host);166LLDB_LOGF(log, "GetClangResourceDir() => '%s'",167g_cached_resource_dir.GetPath().c_str());168});169return g_cached_resource_dir;170}171172173