diff options
Diffstat (limited to 'lldb/source/Utility/XcodeSDK.cpp')
-rw-r--r-- | lldb/source/Utility/XcodeSDK.cpp | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp new file mode 100644 index 0000000000000..066bf457966c9 --- /dev/null +++ b/lldb/source/Utility/XcodeSDK.cpp @@ -0,0 +1,309 @@ +//===-- XcodeSDK.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/XcodeSDK.h" +#include "lldb/Utility/FileSpec.h" + +#include "lldb/lldb-types.h" + +#include "llvm/ADT/Triple.h" + +#include <string> + +using namespace lldb; +using namespace lldb_private; + +static llvm::StringRef GetName(XcodeSDK::Type type) { + switch (type) { + case XcodeSDK::MacOSX: + return "MacOSX"; + case XcodeSDK::iPhoneSimulator: + return "iPhoneSimulator"; + case XcodeSDK::iPhoneOS: + return "iPhoneOS"; + case XcodeSDK::AppleTVSimulator: + return "AppleTVSimulator"; + case XcodeSDK::AppleTVOS: + return "AppleTVOS"; + case XcodeSDK::WatchSimulator: + return "WatchSimulator"; + case XcodeSDK::watchOS: + return "WatchOS"; + case XcodeSDK::bridgeOS: + return "bridgeOS"; + case XcodeSDK::Linux: + return "Linux"; + case XcodeSDK::unknown: + return {}; + } + llvm_unreachable("Unhandled sdk type!"); +} + +XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) { + if (!m_name.empty()) { + if (!info.version.empty()) + m_name += info.version.getAsString(); + if (info.internal) + m_name += ".Internal"; + m_name += ".sdk"; + } +} + +XcodeSDK &XcodeSDK::operator=(XcodeSDK other) { + m_name = other.m_name; + return *this; +} + +bool XcodeSDK::operator==(XcodeSDK other) { + return m_name == other.m_name; +} + +static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) { + if (name.consume_front("MacOSX")) + return XcodeSDK::MacOSX; + if (name.consume_front("iPhoneSimulator")) + return XcodeSDK::iPhoneSimulator; + if (name.consume_front("iPhoneOS")) + return XcodeSDK::iPhoneOS; + if (name.consume_front("AppleTVSimulator")) + return XcodeSDK::AppleTVSimulator; + if (name.consume_front("AppleTVOS")) + return XcodeSDK::AppleTVOS; + if (name.consume_front("WatchSimulator")) + return XcodeSDK::WatchSimulator; + if (name.consume_front("WatchOS")) + return XcodeSDK::watchOS; + if (name.consume_front("bridgeOS")) + return XcodeSDK::bridgeOS; + if (name.consume_front("Linux")) + return XcodeSDK::Linux; + static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1, + "New SDK type was added, update this list!"); + return XcodeSDK::unknown; +} + +static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) { + unsigned i = 0; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + + llvm::VersionTuple version; + version.tryParse(name.slice(0, i - 1)); + name = name.drop_front(i); + return version; +} + +static bool ParseAppleInternalSDK(llvm::StringRef &name) { + return name.consume_front("Internal.") || name.consume_front(".Internal."); +} + +XcodeSDK::Info XcodeSDK::Parse() const { + XcodeSDK::Info info; + llvm::StringRef input(m_name); + info.type = ParseSDKName(input); + info.version = ParseSDKVersion(input); + info.internal = ParseAppleInternalSDK(input); + return info; +} + +bool XcodeSDK::IsAppleInternalSDK() const { + llvm::StringRef input(m_name); + ParseSDKName(input); + ParseSDKVersion(input); + return ParseAppleInternalSDK(input); +} + +llvm::VersionTuple XcodeSDK::GetVersion() const { + llvm::StringRef input(m_name); + ParseSDKName(input); + return ParseSDKVersion(input); +} + +XcodeSDK::Type XcodeSDK::GetType() const { + llvm::StringRef input(m_name); + return ParseSDKName(input); +} + +llvm::StringRef XcodeSDK::GetString() const { return m_name; } + +bool XcodeSDK::Info::operator<(const Info &other) const { + return std::tie(type, version, internal) < + std::tie(other.type, other.version, other.internal); +} + +bool XcodeSDK::Info::operator==(const Info &other) const { + return std::tie(type, version, internal) == + std::tie(other.type, other.version, other.internal); +} + +void XcodeSDK::Merge(XcodeSDK other) { + // The "bigger" SDK always wins. + 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 (!l.internal && r.internal) + m_name = + m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk"); + } +} + +std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) { + std::string name; + switch (info.type) { + case MacOSX: + name = "macosx"; + break; + case iPhoneSimulator: + name = "iphonesimulator"; + break; + case iPhoneOS: + name = "iphoneos"; + break; + case AppleTVSimulator: + name = "appletvsimulator"; + break; + case AppleTVOS: + name = "appletvos"; + break; + case WatchSimulator: + name = "watchsimulator"; + break; + case watchOS: + name = "watchos"; + break; + case bridgeOS: + name = "bridgeos"; + break; + case Linux: + name = "linux"; + break; + case unknown: + return {}; + } + if (!info.version.empty()) + name += info.version.getAsString(); + if (info.internal) + name += ".internal"; + return name; +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, + llvm::VersionTuple version) { + switch (sdk_type) { + case Type::MacOSX: + return version >= llvm::VersionTuple(10, 10); + case Type::iPhoneOS: + case Type::iPhoneSimulator: + case Type::AppleTVOS: + case Type::AppleTVSimulator: + return version >= llvm::VersionTuple(8); + case Type::watchOS: + case Type::WatchSimulator: + return version >= llvm::VersionTuple(6); + default: + return false; + } + + return false; +} + +bool XcodeSDK::SupportsSwift() const { + XcodeSDK::Info info = Parse(); + switch (info.type) { + case Type::MacOSX: + return info.version.empty() || info.version >= llvm::VersionTuple(10, 10); + case Type::iPhoneOS: + case Type::iPhoneSimulator: + return info.version.empty() || info.version >= llvm::VersionTuple(8); + case Type::AppleTVSimulator: + case Type::AppleTVOS: + return info.version.empty() || info.version >= llvm::VersionTuple(9); + case Type::WatchSimulator: + case Type::watchOS: + return info.version.empty() || info.version >= llvm::VersionTuple(2); + case Type::Linux: + return true; + default: + return false; + } +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type, + const FileSpec &sdk_path) { + ConstString last_path_component = sdk_path.GetLastPathComponent(); + + if (!last_path_component) + return false; + + XcodeSDK sdk(last_path_component.GetStringRef().str()); + if (sdk.GetType() != desired_type) + return false; + return SDKSupportsModules(sdk.GetType(), sdk.GetVersion()); +} + +XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) { + using namespace llvm; + switch (triple.getOS()) { + case Triple::MacOSX: + case Triple::Darwin: + return XcodeSDK::MacOSX; + case Triple::IOS: + switch (triple.getEnvironment()) { + case Triple::MacABI: + return XcodeSDK::MacOSX; + case Triple::Simulator: + return XcodeSDK::iPhoneSimulator; + default: + return XcodeSDK::iPhoneOS; + } + case Triple::TvOS: + if (triple.getEnvironment() == Triple::Simulator) + return XcodeSDK::AppleTVSimulator; + return XcodeSDK::AppleTVOS; + case Triple::WatchOS: + if (triple.getEnvironment() == Triple::Simulator) + return XcodeSDK::WatchSimulator; + return XcodeSDK::watchOS; + case Triple::Linux: + return XcodeSDK::Linux; + default: + return XcodeSDK::unknown; + } +} + +std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { + auto begin = llvm::sys::path::begin(path); + auto end = llvm::sys::path::end(path); + + // Iterate over the path components until we find something that ends with + // .app. If the next component is Contents then we've found the Contents + // directory. + for (auto it = begin; it != end; ++it) { + if (it->endswith(".app")) { + auto next = it; + if (++next != end && *next == "Contents") { + llvm::SmallString<128> buffer; + llvm::sys::path::append(buffer, begin, ++next, + llvm::sys::path::Style::posix); + return buffer.str().str(); + } + } + } + + return {}; +} |