Skip to content

Commit 2665e74

Browse files
committed
[lldb]HostInfoMacOSX] Search CommandLineTools directory when looking up SDK paths
`GetSDKRoot` uses `xcrun` to find an SDK root path for a given SDK version string. But if the SDK doesn't exist in the Xcode installations, but instead lives in the `CommandLineTools`, `xcrun` will fail to find it. Negative searches for an SDK path cost a lot (a few seconds) each time `xcrun` is invoked. We do cache negative results in `find_cached_path` inside LLDB, but we would still pay the price on every new debug session the first time we evaluate an expression. This doesn't only cause a noticable delay in running the expression, but also generates following error: ``` error: Error while searching for Xcode SDK: timed out waiting for shell command to complete (int) $0 = 42 ``` To avoid this `xcrun` penalty, we search `CommandLineTools` for a matching SDK ourselves, and only if we don't find it, do we fall back to calling `xcrun`. rdar://113619904 rdar://113619723
1 parent 134a94a commit 2665e74

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

lldb/include/lldb/Host/FileSystem.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,9 @@ class FileSystem {
183183
eEnumerateDirectoryResultQuit
184184
};
185185

186-
typedef EnumerateDirectoryResult (*EnumerateDirectoryCallbackType)(
187-
void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef);
186+
typedef std::function<EnumerateDirectoryResult(
187+
void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef)>
188+
EnumerateDirectoryCallbackType;
188189

189190
typedef std::function<EnumerateDirectoryResult(
190191
llvm::sys::fs::file_type file_type, llvm::StringRef)>

lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
#include "lldb/Utility/Log.h"
1616
#include "lldb/Utility/Timer.h"
1717

18+
#include "clang/Basic/DarwinSDKInfo.h"
1819
#include "llvm/ADT/ScopeExit.h"
1920
#include "llvm/ADT/SmallString.h"
2021
#include "llvm/ADT/StringMap.h"
22+
#include "llvm/Support/Error.h"
2123
#include "llvm/Support/FileSystem.h"
2224
#include "llvm/Support/Path.h"
25+
#include "llvm/Support/VersionTuple.h"
2326
#include "llvm/Support/raw_ostream.h"
2427

2528
// C++ Includes
@@ -569,10 +572,52 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
569572
cache.insert({key, {error, true}});
570573
return llvm::createStringError(llvm::inconvertibleErrorCode(), error);
571574
}
575+
576+
if (path_or_err->empty())
577+
return llvm::createStringError("Empty path determined for '%s'",
578+
key.data());
579+
572580
auto it_new = cache.insert({key, {*path_or_err, false}});
573581
return it_new.first->second.str;
574582
}
575583

584+
static llvm::Expected<std::string>
585+
GetCommandLineToolsSDKRoot(llvm::VersionTuple version) {
586+
std::string clt_root_dir;
587+
FileSystem::Instance().EnumerateDirectory(
588+
"/Library/Developer/CommandLineTools/SDKs/", /*find_directories=*/true,
589+
/*find_files=*/false, /*find_other=*/false,
590+
[&](void *baton, llvm::sys::fs::file_type file_type,
591+
llvm::StringRef name) {
592+
assert(file_type == llvm::sys::fs::file_type::directory_file);
593+
594+
if (!name.ends_with(".sdk"))
595+
return FileSystem::eEnumerateDirectoryResultNext;
596+
597+
llvm::Expected<std::optional<clang::DarwinSDKInfo>> sdk_info =
598+
clang::parseDarwinSDKInfo(
599+
*FileSystem::Instance().GetVirtualFileSystem(), name);
600+
if (!sdk_info) {
601+
LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), sdk_info.takeError(),
602+
"Error while parsing {1}: {0}", name);
603+
return FileSystem::eEnumerateDirectoryResultNext;
604+
}
605+
606+
if (!*sdk_info)
607+
return FileSystem::eEnumerateDirectoryResultNext;
608+
609+
if (version == (*sdk_info)->getVersion()) {
610+
clt_root_dir = name;
611+
return FileSystem::eEnumerateDirectoryResultQuit;
612+
}
613+
614+
return FileSystem::eEnumerateDirectoryResultNext;
615+
},
616+
/*baton=*/nullptr);
617+
618+
return clt_root_dir;
619+
}
620+
576621
llvm::Expected<llvm::StringRef> HostInfoMacOSX::GetSDKRoot(SDKOptions options) {
577622
static llvm::StringMap<ErrorOrPath> g_sdk_path;
578623
static std::mutex g_sdk_path_mutex;
@@ -581,6 +626,21 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
581626
"XcodeSDK not specified");
582627
XcodeSDK sdk = *options.XcodeSDKSelection;
583628
auto key = sdk.GetString();
629+
630+
// xcrun doesn't search SDKs in the CommandLineTools (CLT) directory. So if
631+
// a program was compiled against a CLT SDK, but that SDK wasn't present in
632+
// any of the Xcode installations, then xcrun would fail to find the SDK
633+
// (which is expensive). To avoid this we first try to find the specified SDK
634+
// in the CLT directory.
635+
auto clt_root_dir = find_cached_path(g_sdk_path, g_sdk_path_mutex, key, [&] {
636+
return GetCommandLineToolsSDKRoot(sdk.GetVersion());
637+
});
638+
639+
if (clt_root_dir)
640+
return clt_root_dir;
641+
else
642+
llvm::consumeError(clt_root_dir.takeError());
643+
584644
return find_cached_path(g_sdk_path, g_sdk_path_mutex, key, [&](){
585645
return GetXcodeSDK(sdk);
586646
});

0 commit comments

Comments
 (0)