summaryrefslogtreecommitdiff
path: root/lldb/source/Utility/XcodeSDK.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Utility/XcodeSDK.cpp')
-rw-r--r--lldb/source/Utility/XcodeSDK.cpp309
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 {};
+}