LLDB mainline
ClangHost.cpp
Go to the documentation of this file.
1//===-- ClangHost.cpp -----------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ClangHost.h"
10
11#include "clang/Basic/Version.h"
12#include "clang/Config/config.h"
13
14#include "llvm/ADT/StringRef.h"
15#include "llvm/ADT/Twine.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/Threading.h"
18
19#include "lldb/Host/Config.h"
21#include "lldb/Host/HostInfo.h"
24#include "lldb/Utility/Log.h"
25
26#include <string>
27
28using namespace lldb_private;
29
30static bool VerifyClangPath(const llvm::Twine &clang_path) {
31 if (FileSystem::Instance().IsDirectory(clang_path))
32 return true;
33 Log *log = GetLog(LLDBLog::Host);
34 LLDB_LOGF(log,
35 "VerifyClangPath(): "
36 "failed to stat clang resource directory at \"%s\"",
37 clang_path.str().c_str());
38 return false;
39}
40
41///
42/// This will compute the clang resource directory assuming that clang was
43/// 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///
49 FileSpec &file_spec,
50 bool verify) {
51 Log *log = GetLog(LLDBLog::Host);
52 std::string raw_path = lldb_shlib_spec.GetPath();
53 llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);
54
55 static const llvm::StringRef kResourceDirSuffixes[] = {
56 // LLVM.org's build of LLDB uses the clang resource directory placed
57 // in $install_dir/lib{,64}/clang/$clang_version.
58 CLANG_INSTALL_LIBDIR_BASENAME "/clang/" CLANG_VERSION_MAJOR_STRING,
59 // swift-lldb uses the clang resource directory copied from swift, which
60 // by default is placed in $install_dir/lib{,64}/lldb/clang. LLDB places
61 // it there, so we use LLDB_INSTALL_LIBDIR_BASENAME.
62 LLDB_INSTALL_LIBDIR_BASENAME "/lldb/clang",
63 };
64
65 for (const auto &Suffix : kResourceDirSuffixes) {
66 llvm::SmallString<256> clang_dir(parent_dir);
67 llvm::SmallString<32> relative_path(Suffix);
68 llvm::sys::path::native(relative_path);
69 llvm::sys::path::append(clang_dir, relative_path);
70 if (!verify || VerifyClangPath(clang_dir)) {
71 LLDB_LOG(log,
72 "DefaultComputeClangResourceDir: Setting ClangResourceDir "
73 "to \"{0}\", verify = {1}",
74 clang_dir.str(), verify ? "true" : "false");
75 file_spec.SetDirectory(clang_dir);
76 FileSystem::Instance().Resolve(file_spec);
77 return true;
78 }
79 }
80
81 return false;
82}
83
85 FileSpec &file_spec, bool verify) {
86#if !defined(__APPLE__)
87 return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,
88 verify);
89#else
90 std::string raw_path = lldb_shlib_spec.GetPath();
91
92 auto rev_it = llvm::sys::path::rbegin(raw_path);
93 auto r_end = llvm::sys::path::rend(raw_path);
94
95 // Check for a Posix-style build of LLDB.
96 while (rev_it != r_end) {
97 if (*rev_it == "LLDB.framework")
98 break;
99 ++rev_it;
100 }
101
102 // We found a non-framework build of LLDB
103 if (rev_it == r_end)
104 return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,
105 verify);
106
107 // Inside Xcode and in Xcode toolchains LLDB is always in lockstep
108 // with the Swift compiler, so it can reuse its Clang resource
109 // directory. This allows LLDB and the Swift compiler to share the
110 // same Clang module cache.
111 llvm::SmallString<256> clang_path;
112 const char *swift_clang_resource_dir = "usr/lib/swift/clang";
113 auto parent = std::next(rev_it);
114 if (parent != r_end && *parent == "SharedFrameworks") {
115 // This is the top-level LLDB in the Xcode.app bundle.
116 // E.g., "Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A"
117 raw_path.resize(parent - r_end);
118 llvm::sys::path::append(clang_path, raw_path,
119 "Developer/Toolchains/XcodeDefault.xctoolchain",
120 swift_clang_resource_dir);
121 if (!verify || VerifyClangPath(clang_path)) {
122 file_spec.SetDirectory(clang_path);
123 FileSystem::Instance().Resolve(file_spec);
124 return true;
125 }
126 } else if (parent != r_end && *parent == "PrivateFrameworks" &&
127 std::distance(parent, r_end) > 2) {
128 ++parent;
129 ++parent;
130 if (*parent == "System") {
131 // This is LLDB inside an Xcode toolchain.
132 // E.g., "Xcode.app/Contents/Developer/Toolchains/" \
133 // "My.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework"
134 raw_path.resize(parent - r_end);
135 llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir);
136 if (!verify || VerifyClangPath(clang_path)) {
137 file_spec.SetDirectory(clang_path);
138 FileSystem::Instance().Resolve(file_spec);
139 return true;
140 }
141 }
142 }
143
144 // Fall back to the Clang resource directory inside the framework.
145 raw_path = lldb_shlib_spec.GetPath();
146 raw_path.resize(rev_it - r_end);
147 raw_path.append("LLDB.framework/Resources/Clang");
148 file_spec.SetDirectory(raw_path);
149 FileSystem::Instance().Resolve(file_spec);
150 return true;
151#endif // __APPLE__
152}
153
155 static FileSpec g_cached_resource_dir;
156 static llvm::once_flag g_once_flag;
157 llvm::call_once(g_once_flag, []() {
158 if (FileSpec lldb_file_spec = HostInfo::GetShlibDir())
159 ComputeClangResourceDirectory(lldb_file_spec, g_cached_resource_dir,
160 true);
161 Log *log = GetLog(LLDBLog::Host);
162 LLDB_LOGF(log, "GetClangResourceDir() => '%s'",
163 g_cached_resource_dir.GetPath().c_str());
164 });
165 return g_cached_resource_dir;
166}
static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, FileSpec &file_spec, bool verify)
This will compute the clang resource directory assuming that clang was installed with the same prefix...
Definition: ClangHost.cpp:48
static bool VerifyClangPath(const llvm::Twine &clang_path)
Definition: ClangHost.cpp:30
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:337
#define LLDB_LOGF(log,...)
Definition: Log.h:344
A file utility class.
Definition: FileSpec.h:56
void SetDirectory(ConstString directory)
Directory string set accessor.
Definition: FileSpec.cpp:334
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:366
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
static FileSystem & Instance()
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:309
FileSpec GetClangResourceDir()
Definition: ClangHost.cpp:154
bool ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, FileSpec &file_spec, bool verify)
Definition: ClangHost.cpp:84