HostInfoMacOS: Add a utility function for finding an SDK-specific tool
authorAdrian Prantl <aprantl@apple.com>
Fri, 26 May 2023 21:48:37 +0000 (14:48 -0700)
committerAdrian Prantl <aprantl@apple.com>
Wed, 31 May 2023 21:46:35 +0000 (14:46 -0700)
This is an API needed by swift-lldb.

https://reviews.llvm.org/D151591

lldb/include/lldb/Host/HostInfoBase.h
lldb/include/lldb/Host/macosx/HostInfoMacOSX.h
lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm
lldb/unittests/Host/HostInfoTest.cpp

index 4082cd7..705aad5 100644 (file)
@@ -16,6 +16,7 @@
 #include "lldb/Utility/XcodeSDK.h"
 #include "lldb/lldb-enumerations.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
 
 #include <cstdint>
 
@@ -135,6 +136,12 @@ public:
     return llvm::make_error<HostInfoError>("cannot determine SDK root");
   }
 
+  /// Return the path to a specific tool in the specified Xcode SDK.
+  static llvm::Expected<llvm::StringRef> FindSDKTool(XcodeSDK sdk,
+                                                     llvm::StringRef tool) {
+    return llvm::errorCodeToError(llvm::errc::no_such_file_or_directory);
+  }
+
   /// Return information about module \p image_name if it is loaded in
   /// the current process's address space.
   static SharedCacheImageInfo
index 74d979d..8eb2ede 100644 (file)
@@ -12,6 +12,7 @@
 #include "lldb/Host/posix/HostInfoPosix.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/XcodeSDK.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/VersionTuple.h"
 #include <optional>
 
@@ -32,6 +33,8 @@ public:
 
   /// Query xcrun to find an Xcode SDK directory.
   static llvm::Expected<llvm::StringRef> GetSDKRoot(SDKOptions options);
+  static llvm::Expected<llvm::StringRef> FindSDKTool(XcodeSDK sdk,
+                                                     llvm::StringRef tool);
 
   /// Shared cache utilities
   static SharedCacheImageInfo
index 96461f9..c80d200 100644 (file)
@@ -523,41 +523,69 @@ static llvm::Expected<std::string> GetXcodeSDK(XcodeSDK sdk) {
   return path;
 }
 
-llvm::Expected<llvm::StringRef> HostInfoMacOSX::GetSDKRoot(SDKOptions options) {
-  struct ErrorOrPath {
-    std::string str;
-    bool is_error;
-  };
-  static llvm::StringMap<ErrorOrPath> g_sdk_path;
-  static std::mutex g_sdk_path_mutex;
+namespace {
+struct ErrorOrPath {
+  std::string str;
+  bool is_error;
+};
+} // namespace
 
-  std::lock_guard<std::mutex> guard(g_sdk_path_mutex);
+static llvm::Expected<llvm::StringRef>
+find_cached_path(llvm::StringMap<ErrorOrPath> &cache, std::mutex &mutex,
+                 llvm::StringRef key,
+                 std::function<llvm::Expected<std::string>(void)> compute) {
+  std::lock_guard<std::mutex> guard(mutex);
   LLDB_SCOPED_TIMER();
 
-  if (!options.XcodeSDKSelection)
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "XCodeSDK not specified");
-  XcodeSDK sdk = *options.XcodeSDKSelection;
-
-  auto key = sdk.GetString();
-  auto it = g_sdk_path.find(key);
-  if (it != g_sdk_path.end()) {
+  auto it = cache.find(key);
+  if (it != cache.end()) {
     if (it->second.is_error)
       return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                      it->second.str);
-    else
-      return it->second.str;
+    return it->second.str;
   }
-  auto path_or_err = GetXcodeSDK(sdk);
+  auto path_or_err = compute();
   if (!path_or_err) {
     std::string error = toString(path_or_err.takeError());
-    g_sdk_path.insert({key, {error, true}});
+    cache.insert({key, {error, true}});
     return llvm::createStringError(llvm::inconvertibleErrorCode(), error);
   }
-  auto it_new = g_sdk_path.insert({key, {*path_or_err, false}});
+  auto it_new = cache.insert({key, {*path_or_err, false}});
   return it_new.first->second.str;
 }
 
+llvm::Expected<llvm::StringRef> HostInfoMacOSX::GetSDKRoot(SDKOptions options) {
+  static llvm::StringMap<ErrorOrPath> g_sdk_path;
+  static std::mutex g_sdk_path_mutex;
+  if (!options.XcodeSDKSelection)
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "XcodeSDK not specified");
+  XcodeSDK sdk = *options.XcodeSDKSelection;
+  auto key = sdk.GetString();
+  return find_cached_path(g_sdk_path, g_sdk_path_mutex, key, [&](){
+    return GetXcodeSDK(sdk);
+  });
+}
+
+llvm::Expected<llvm::StringRef>
+HostInfoMacOSX::FindSDKTool(XcodeSDK sdk, llvm::StringRef tool) {
+  static llvm::StringMap<ErrorOrPath> g_tool_path;
+  static std::mutex g_tool_path_mutex;
+  std::string key;
+  llvm::raw_string_ostream(key) << sdk.GetString() << ":" << tool;
+  return find_cached_path(
+      g_tool_path, g_tool_path_mutex, key,
+      [&]() -> llvm::Expected<std::string> {
+        std::string sdk_name = XcodeSDK::GetCanonicalName(sdk.Parse());
+        if (sdk_name.empty())
+          return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                         "Unrecognized SDK type: " +
+                                             sdk.GetString());
+        llvm::SmallVector<llvm::StringRef, 2> find = {"-find", tool};
+        return xcrun(sdk_name, find);
+      });
+}
+
 namespace {
 struct dyld_shared_cache_dylib_text_info {
   uint64_t version; // current version 1
index 322675c..5c53b96 100644 (file)
@@ -73,6 +73,23 @@ TEST_F(HostInfoTest, GetXcodeSDK) {
   // This is expected to fail.
   EXPECT_TRUE(get_sdk("CeciNestPasUnOS.sdk", true).empty());
 }
+
+TEST_F(HostInfoTest, FindSDKTool) {
+  auto find_tool = [](std::string sdk, llvm::StringRef tool,
+                      bool error = false) -> llvm::StringRef {
+    auto sdk_path_or_err =
+        HostInfo::FindSDKTool(XcodeSDK(std::move(sdk)), tool);
+    if (!error) {
+      EXPECT_TRUE((bool)sdk_path_or_err);
+      return *sdk_path_or_err;
+    }
+    EXPECT_FALSE((bool)sdk_path_or_err);
+    llvm::consumeError(sdk_path_or_err.takeError());
+    return {};
+  };
+  EXPECT_FALSE(find_tool("MacOSX.sdk", "clang").empty());
+  EXPECT_TRUE(find_tool("MacOSX.sdk", "CeciNestPasUnOutil").empty());
+}
 #endif
 
 TEST(HostInfoTestInitialization, InitTwice) {