Index: lldb/include/lldb/Utility/XcodeSDK.h =================================================================== --- lldb/include/lldb/Utility/XcodeSDK.h +++ lldb/include/lldb/Utility/XcodeSDK.h @@ -38,7 +38,6 @@ numSDKTypes, unknown = -1 }; - static llvm::StringRef GetNameForType(Type type); /// The merge function follows a strict order to maintain monotonicity: /// 1. SDK with the higher SDKType wins. @@ -50,14 +49,18 @@ bool operator==(XcodeSDK other); /// Return parsed SDK number, and SDK version number. - std::tuple Parse() const; + std::tuple Parse() const; + bool IsAppleInternalSDK() const; llvm::VersionTuple GetVersion() const; Type GetType() const; llvm::StringRef GetString() const; static bool SDKSupportsModules(Type type, llvm::VersionTuple version); static bool SDKSupportsModules(Type desired_type, const FileSpec &sdk_path); - static llvm::StringRef GetSDKNameForType(Type type); + /// Return the canonical SDK name, such as "macosx" for the macOS SDK. + static std::string GetCanonicalNameFor(Type type, + llvm::VersionTuple version = {}, + bool internal = false); }; } // namespace lldb_private Index: lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm =================================================================== --- lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -298,37 +298,73 @@ } std::string HostInfoMacOSX::GetXcodeSDK(XcodeSDK sdk) { - std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + - XcodeSDK::GetSDKNameForType(sdk.GetType()).str(); - llvm::VersionTuple version = sdk.GetVersion(); - if (!version.empty()) - xcrun_cmd += version.getAsString(); - - int status = 0; - int signo = 0; - std::string output_str; - lldb_private::Status error = - Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, - &output_str, std::chrono::seconds(15)); - - // Check that xcrun return something useful. - if (status != 0 || output_str.empty()) + XcodeSDK::Type sdk_type; + llvm::VersionTuple sdk_version; + bool internal; + std::tie(sdk_type, sdk_version, internal) = sdk.Parse(); + auto sdk_name = XcodeSDK::GetCanonicalNameFor(sdk_type, sdk_version, internal); + auto find_sdk = [](std::string sdk_name) -> std::string { + std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + sdk_name; + int status = 0; + int signo = 0; + std::string output_str; + lldb_private::Status error = + Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, + &output_str, std::chrono::seconds(15)); + + // Check that xcrun return something useful. + if (status != 0 || output_str.empty()) + return {}; + + // Convert to a StringRef so we can manipulate the string without modifying + // the underlying data. + llvm::StringRef output(output_str); + + // Remove any trailing newline characters. + output = output.rtrim(); + + // Strip any leading newline characters and everything before them. + const size_t last_newline = output.rfind('\n'); + if (last_newline != llvm::StringRef::npos) + output = output.substr(last_newline + 1); + + return output.str(); + }; + + std::string path = find_sdk(sdk_name); + while (path.empty()) { + // Try a future-proof version of the name. + if (sdk_type == XcodeSDK::Type::MacOSX && !sdk_version.empty() && internal) { + llvm::StringRef fixed(sdk_name); + if (fixed.consume_back("internal")) + sdk_name = fixed.str()+".internal"; + path = find_sdk(sdk_name); + if (!path.empty()) + break; + } + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + LLDB_LOGF(log, "Couldn't find SDK %s on host", sdk_name.c_str()); + + // Try without the version. + sdk_name = XcodeSDK::GetCanonicalNameFor(sdk_type, {}, internal); + path = find_sdk(sdk_name); + if (!path.empty()) + break; + + LLDB_LOGF(log, "Couldn't find SDK %s on host", sdk_name.c_str()); + + // Try without internal. + sdk_name = XcodeSDK::GetCanonicalNameFor(sdk_type, {}, false); + path = find_sdk(sdk_name); + if (!path.empty()) + break; + + LLDB_LOGF(log, "Couldn't find any matching SDK on host"); return {}; - - // Convert to a StringRef so we can manipulate the string without modifying - // the underlying data. - llvm::StringRef output(output_str); - - // Remove any trailing newline characters. - output = output.rtrim(); - - // Strip any leading newline characters and everything before them. - const size_t last_newline = output.rfind('\n'); - if (last_newline != llvm::StringRef::npos) - output = output.substr(last_newline + 1); + } // Whatever is left in output should be a valid path. - if (!FileSystem::Instance().Exists(output)) + if (!FileSystem::Instance().Exists(path)) return {}; - return output.str(); + return path; } Index: lldb/source/Utility/XcodeSDK.cpp =================================================================== --- lldb/source/Utility/XcodeSDK.cpp +++ lldb/source/Utility/XcodeSDK.cpp @@ -64,13 +64,24 @@ return version; } +static bool ParseAppleInternalSDK(llvm::StringRef &name) { + return name.consume_front("Internal."); +} -std::tuple XcodeSDK::Parse() const { +std::tuple XcodeSDK::Parse() const { llvm::StringRef input(m_name); XcodeSDK::Type sdk = ParseSDKName(input); llvm::VersionTuple version = ParseSDKVersion(input); + bool internal = ParseAppleInternalSDK(input); return std::make_tuple( - std::move(sdk), std::move(version)); + std::move(sdk), std::move(version), internal); +} + +bool XcodeSDK::IsAppleInternalSDK() const { + llvm::StringRef input(m_name); + ParseSDKName(input); + ParseSDKVersion(input); + return ParseAppleInternalSDK(input); } llvm::VersionTuple XcodeSDK::GetVersion() const { @@ -88,35 +99,64 @@ void XcodeSDK::Merge(XcodeSDK other) { // The "bigger" SDK always wins. - if (Parse() < other.Parse()) + auto l = Parse(); + auto r = other.Parse(); + if (l < r) *this = other; + else { + // The Internal flag always wins. + if (llvm::StringRef(m_name).endswith(".sdk")) + if (!std::get<2>(l) && std::get<2>(r)) + m_name = + m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk"); + } } -llvm::StringRef XcodeSDK::GetSDKNameForType(XcodeSDK::Type type) { +std::string XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type type, + llvm::VersionTuple version, + bool internal) { + std::string name; switch (type) { case MacOSX: - return "macosx"; + name = "macosx"; + break; case iPhoneSimulator: - return "iphonesimulator"; + name = "iphonesimulator"; + break; case iPhoneOS: - return "iphoneos"; + name = "iphoneos"; + break; case AppleTVSimulator: - return "appletvsimulator"; + name = "appletvsimulator"; + break; case AppleTVOS: - return "appletvos"; + name = "appletvos"; + break; case WatchSimulator: - return "watchsimulator"; + name = "watchsimulator"; + break; case watchOS: - return "watchos"; + name = "watchos"; + break; case bridgeOS: - return "bridgeos"; + name = "bridgeos"; + break; case Linux: - return "linux"; + name = "linux"; + break; case numSDKTypes: case unknown: - return ""; + return {}; + } + if (!version.empty()) + name += version.getAsString(); + if (internal) { + // For historic reasons. + if (type != MacOSX || version.empty()) + name += '.'; + name += "internal"; } - llvm_unreachable("unhandled switch case"); + return name; } bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, @@ -147,12 +187,13 @@ const llvm::StringRef sdk_name = last_path_component.GetStringRef(); const std::string sdk_name_lower = sdk_name.lower(); - const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); + const llvm::StringRef sdk_string = GetCanonicalNameFor(desired_type); if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) return false; auto version_part = sdk_name.drop_front(sdk_string.size()); version_part.consume_back(".sdk"); + version_part.consume_back(".Internal"); llvm::VersionTuple version; if (version.tryParse(version_part)) Index: lldb/unittests/Host/HostInfoTest.cpp =================================================================== --- lldb/unittests/Host/HostInfoTest.cpp +++ lldb/unittests/Host/HostInfoTest.cpp @@ -50,3 +50,14 @@ std::string s("abc"); EXPECT_TRUE(HostInfo::GetHostname(s)); } + +#if defined(__APPLE__) +TEST_F(HostInfoTest, GetXcodeSDK) { + EXPECT_FALSE(HostInfo::GetXcodeSDK(XcodeSDK("MacOSX.sdk")).empty()); + // These are expected to fall back to an available version. + EXPECT_FALSE(HostInfo::GetXcodeSDK(XcodeSDK("MacOSX9999.sdk")).empty()); + EXPECT_FALSE(HostInfo::GetXcodeSDK(XcodeSDK("MacOSX10.15.Internal.sdk")).empty()); + // This is expected to fail. + EXPECT_TRUE(HostInfo::GetXcodeSDK(XcodeSDK("CeciNestPasUnOS.sdk")).empty()); +} +#endif Index: lldb/unittests/Utility/XcodeSDKTest.cpp =================================================================== --- lldb/unittests/Utility/XcodeSDKTest.cpp +++ lldb/unittests/Utility/XcodeSDKTest.cpp @@ -30,6 +30,10 @@ EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetVersion(), llvm::VersionTuple()); EXPECT_EQ(XcodeSDK("MacOSX10.9.sdk").GetVersion(), llvm::VersionTuple(10, 9)); EXPECT_EQ(XcodeSDK("MacOSX10.15.4.sdk").GetVersion(), llvm::VersionTuple(10, 15)); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").IsAppleInternalSDK(), false); + EXPECT_EQ(XcodeSDK("MacOSX10.15.Internal.sdk").GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("MacOSX10.15.Internal.sdk").GetVersion(), llvm::VersionTuple(10, 15)); + EXPECT_EQ(XcodeSDK("MacOSX10.15.Internal.sdk").IsAppleInternalSDK(), true); EXPECT_EQ(XcodeSDK().GetType(), XcodeSDK::unknown); EXPECT_EQ(XcodeSDK().GetVersion(), llvm::VersionTuple()); } @@ -46,6 +50,12 @@ EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(1, 1)); sdk.Merge(XcodeSDK("WatchOS2.0.sdk")); EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0)); + sdk.Merge(XcodeSDK("WatchOS1.1.Internal.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0)); + EXPECT_EQ(sdk.IsAppleInternalSDK(), true); + XcodeSDK empty; + empty.Merge(XcodeSDK("MacOSX10.14.Internal.sdk")); + EXPECT_EQ(empty.GetString(), llvm::StringRef("MacOSX10.14.Internal.sdk")); } TEST(XcodeSDKTest, SDKSupportsModules) { @@ -55,6 +65,10 @@ FileSpec( base + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec(base + "iPhoneSimulator.platform/Developer/SDKs/" + "iPhoneSimulator12.0.Internal.sdk"))); EXPECT_FALSE(XcodeSDK::SDKSupportsModules( XcodeSDK::Type::iPhoneSimulator, FileSpec( @@ -68,19 +82,42 @@ FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); } -TEST(XcodeSDKTest, GetSDKNameForType) { - EXPECT_EQ("macosx", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::MacOSX)); +TEST(XcodeSDKTest, GetCanonicalNameFor) { + EXPECT_EQ("macosx", XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::MacOSX)); EXPECT_EQ("iphonesimulator", - XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneSimulator)); - EXPECT_EQ("iphoneos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneOS)); + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::iPhoneSimulator)); + EXPECT_EQ("iphoneos", XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::iPhoneOS)); EXPECT_EQ("appletvsimulator", - XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVSimulator)); + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::AppleTVSimulator)); EXPECT_EQ("appletvos", - XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVOS)); + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::AppleTVOS)); EXPECT_EQ("watchsimulator", - XcodeSDK::GetSDKNameForType(XcodeSDK::Type::WatchSimulator)); - EXPECT_EQ("watchos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::watchOS)); - EXPECT_EQ("linux", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::Linux)); - EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::numSDKTypes)); - EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::unknown)); + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::WatchSimulator)); + EXPECT_EQ("watchos", XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::watchOS)); + EXPECT_EQ("linux", XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::Linux)); + EXPECT_EQ("", XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::numSDKTypes)); + EXPECT_EQ("", XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::unknown)); + + EXPECT_EQ("macosx.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::MacOSX, {}, true)); + EXPECT_EQ( + "iphonesimulator.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::iPhoneSimulator, {}, true)); + EXPECT_EQ("iphoneos.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::iPhoneOS, {}, true)); + EXPECT_EQ("appletvsimulator.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::AppleTVSimulator, {}, true)); + EXPECT_EQ("appletvos.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::AppleTVOS, {}, true)); + EXPECT_EQ("watchsimulator.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::WatchSimulator, {}, true)); + EXPECT_EQ("watchos.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::watchOS, {}, true)); + + EXPECT_EQ("macosx10.9internal", // sic! + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::MacOSX, + llvm::VersionTuple(10, 9), true)); + EXPECT_EQ("iphoneos7.0.internal", + XcodeSDK::GetCanonicalNameFor(XcodeSDK::Type::iPhoneOS, + llvm::VersionTuple(7, 0), true)); }