[Lldb-commits] [lldb] [lldb]HostInfoMacOSX] Search CommandLineTools directory when looking up SDK paths (PR #128712)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Tue Feb 25 05:23:38 PST 2025


https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/128712

`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

>From 2665e747d5866480f2f704d5a72fe016d258f200 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 25 Feb 2025 13:11:33 +0000
Subject: [PATCH] [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
---
 lldb/include/lldb/Host/FileSystem.h           |  5 +-
 .../Host/macosx/objcxx/HostInfoMacOSX.mm      | 60 +++++++++++++++++++
 2 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/lldb/include/lldb/Host/FileSystem.h b/lldb/include/lldb/Host/FileSystem.h
index 640f3846e448c..4128d7b012041 100644
--- a/lldb/include/lldb/Host/FileSystem.h
+++ b/lldb/include/lldb/Host/FileSystem.h
@@ -183,8 +183,9 @@ class FileSystem {
     eEnumerateDirectoryResultQuit
   };
 
-  typedef EnumerateDirectoryResult (*EnumerateDirectoryCallbackType)(
-      void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef);
+  typedef std::function<EnumerateDirectoryResult(
+      void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef)>
+      EnumerateDirectoryCallbackType;
 
   typedef std::function<EnumerateDirectoryResult(
       llvm::sys::fs::file_type file_type, llvm::StringRef)>
diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
index 6e924fdc684cf..a94fd3b57f9d6 100644
--- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
+++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
@@ -15,11 +15,14 @@
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/Timer.h"
 
+#include "clang/Basic/DarwinSDKInfo.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/VersionTuple.h"
 #include "llvm/Support/raw_ostream.h"
 
 // C++ Includes
@@ -569,10 +572,52 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
     cache.insert({key, {error, true}});
     return llvm::createStringError(llvm::inconvertibleErrorCode(), error);
   }
+
+  if (path_or_err->empty())
+    return llvm::createStringError("Empty path determined for '%s'",
+                                   key.data());
+
   auto it_new = cache.insert({key, {*path_or_err, false}});
   return it_new.first->second.str;
 }
 
+static llvm::Expected<std::string>
+GetCommandLineToolsSDKRoot(llvm::VersionTuple version) {
+  std::string clt_root_dir;
+  FileSystem::Instance().EnumerateDirectory(
+      "/Library/Developer/CommandLineTools/SDKs/", /*find_directories=*/true,
+      /*find_files=*/false, /*find_other=*/false,
+      [&](void *baton, llvm::sys::fs::file_type file_type,
+          llvm::StringRef name) {
+        assert(file_type == llvm::sys::fs::file_type::directory_file);
+
+        if (!name.ends_with(".sdk"))
+          return FileSystem::eEnumerateDirectoryResultNext;
+
+        llvm::Expected<std::optional<clang::DarwinSDKInfo>> sdk_info =
+            clang::parseDarwinSDKInfo(
+                *FileSystem::Instance().GetVirtualFileSystem(), name);
+        if (!sdk_info) {
+          LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions), sdk_info.takeError(),
+                         "Error while parsing {1}: {0}", name);
+          return FileSystem::eEnumerateDirectoryResultNext;
+        }
+
+        if (!*sdk_info)
+          return FileSystem::eEnumerateDirectoryResultNext;
+
+        if (version == (*sdk_info)->getVersion()) {
+          clt_root_dir = name;
+          return FileSystem::eEnumerateDirectoryResultQuit;
+        }
+
+        return FileSystem::eEnumerateDirectoryResultNext;
+      },
+      /*baton=*/nullptr);
+
+  return clt_root_dir;
+}
+
 llvm::Expected<llvm::StringRef> HostInfoMacOSX::GetSDKRoot(SDKOptions options) {
   static llvm::StringMap<ErrorOrPath> g_sdk_path;
   static std::mutex g_sdk_path_mutex;
@@ -581,6 +626,21 @@ static bool ResolveAndVerifyCandidateSupportDir(FileSpec &path) {
                                    "XcodeSDK not specified");
   XcodeSDK sdk = *options.XcodeSDKSelection;
   auto key = sdk.GetString();
+
+  // xcrun doesn't search SDKs in the CommandLineTools (CLT) directory. So if
+  // a program was compiled against a CLT SDK, but that SDK wasn't present in
+  // any of the Xcode installations, then xcrun would fail to find the SDK
+  // (which is expensive). To avoid this we first try to find the specified SDK
+  // in the CLT directory.
+  auto clt_root_dir = find_cached_path(g_sdk_path, g_sdk_path_mutex, key, [&] {
+    return GetCommandLineToolsSDKRoot(sdk.GetVersion());
+  });
+
+  if (clt_root_dir)
+    return clt_root_dir;
+  else
+    llvm::consumeError(clt_root_dir.takeError());
+
   return find_cached_path(g_sdk_path, g_sdk_path_mutex, key, [&](){
     return GetXcodeSDK(sdk);
   });



More information about the lldb-commits mailing list