314 lines · cpp
1//===-- XcodeSDK.cpp ------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Utility/XcodeSDK.h"10#include "lldb/Utility/FileSpec.h"11 12#include "lldb/lldb-types.h"13 14#include "llvm/TargetParser/Triple.h"15 16#include <string>17 18using namespace lldb;19using namespace lldb_private;20 21static llvm::StringRef GetName(XcodeSDK::Type type) {22 switch (type) {23 case XcodeSDK::MacOSX:24 return "MacOSX";25 case XcodeSDK::iPhoneSimulator:26 return "iPhoneSimulator";27 case XcodeSDK::iPhoneOS:28 return "iPhoneOS";29 case XcodeSDK::AppleTVSimulator:30 return "AppleTVSimulator";31 case XcodeSDK::AppleTVOS:32 return "AppleTVOS";33 case XcodeSDK::WatchSimulator:34 return "WatchSimulator";35 case XcodeSDK::watchOS:36 return "WatchOS";37 case XcodeSDK::XRSimulator:38 return "XRSimulator";39 case XcodeSDK::XROS:40 return "XROS";41 case XcodeSDK::BridgeOS:42 return "BridgeOS";43 case XcodeSDK::Linux:44 return "Linux";45 case XcodeSDK::unknown:46 return {};47 }48 llvm_unreachable("Unhandled sdk type!");49}50 51XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) {52 if (!m_name.empty()) {53 if (!info.version.empty())54 m_name += info.version.getAsString();55 if (info.internal)56 m_name += ".Internal";57 m_name += ".sdk";58 }59}60 61XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) = default;62 63bool XcodeSDK::operator==(const XcodeSDK &other) const {64 return m_name == other.m_name;65}66 67static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {68 if (name.consume_front("MacOSX"))69 return XcodeSDK::MacOSX;70 if (name.consume_front("iPhoneSimulator"))71 return XcodeSDK::iPhoneSimulator;72 if (name.consume_front("iPhoneOS"))73 return XcodeSDK::iPhoneOS;74 if (name.consume_front("AppleTVSimulator"))75 return XcodeSDK::AppleTVSimulator;76 if (name.consume_front("AppleTVOS"))77 return XcodeSDK::AppleTVOS;78 if (name.consume_front("WatchSimulator"))79 return XcodeSDK::WatchSimulator;80 if (name.consume_front("WatchOS"))81 return XcodeSDK::watchOS;82 if (name.consume_front("XRSimulator"))83 return XcodeSDK::XRSimulator;84 if (name.consume_front("XROS"))85 return XcodeSDK::XROS;86 if (name.consume_front("BridgeOS"))87 return XcodeSDK::BridgeOS;88 if (name.consume_front("Linux"))89 return XcodeSDK::Linux;90 static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,91 "New SDK type was added, update this list!");92 return XcodeSDK::unknown;93}94 95static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {96 unsigned i = 0;97 while (i < name.size() && name[i] >= '0' && name[i] <= '9')98 ++i;99 if (i == name.size() || name[i++] != '.')100 return {};101 while (i < name.size() && name[i] >= '0' && name[i] <= '9')102 ++i;103 if (i == name.size() || name[i++] != '.')104 return {};105 106 llvm::VersionTuple version;107 version.tryParse(name.slice(0, i - 1));108 name = name.drop_front(i);109 return version;110}111 112static bool ParseAppleInternalSDK(llvm::StringRef &name) {113 return name.consume_front("Internal.") || name.consume_front(".Internal.");114}115 116XcodeSDK::Info XcodeSDK::Parse() const {117 XcodeSDK::Info info;118 llvm::StringRef input(m_name);119 info.type = ParseSDKName(input);120 info.version = ParseSDKVersion(input);121 info.internal = ParseAppleInternalSDK(input);122 return info;123}124 125bool XcodeSDK::IsAppleInternalSDK() const {126 llvm::StringRef input(m_name);127 ParseSDKName(input);128 ParseSDKVersion(input);129 return ParseAppleInternalSDK(input);130}131 132llvm::VersionTuple XcodeSDK::GetVersion() const {133 llvm::StringRef input(m_name);134 ParseSDKName(input);135 return ParseSDKVersion(input);136}137 138XcodeSDK::Type XcodeSDK::GetType() const {139 llvm::StringRef input(m_name);140 return ParseSDKName(input);141}142 143llvm::StringRef XcodeSDK::GetString() const { return m_name; }144 145const FileSpec &XcodeSDK::GetSysroot() const { return m_sysroot; }146 147bool XcodeSDK::Info::operator<(const Info &other) const {148 return std::tie(type, version, internal) <149 std::tie(other.type, other.version, other.internal);150}151 152bool XcodeSDK::Info::operator==(const Info &other) const {153 return std::tie(type, version, internal) ==154 std::tie(other.type, other.version, other.internal);155}156 157void XcodeSDK::Merge(const XcodeSDK &other) {158 // The "bigger" SDK always wins.159 auto l = Parse();160 auto r = other.Parse();161 if (l < r)162 *this = other;163 else {164 // The Internal flag always wins.165 if (!l.internal && r.internal) {166 if (llvm::StringRef(m_name).ends_with(".sdk"))167 m_name =168 m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");169 }170 }171 172 // We changed the SDK name. Adjust the sysroot accordingly.173 if (m_sysroot && m_sysroot.GetFilename().GetStringRef() != m_name)174 m_sysroot.SetFilename(m_name);175}176 177std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {178 std::string name;179 switch (info.type) {180 case MacOSX:181 name = "macosx";182 break;183 case iPhoneSimulator:184 name = "iphonesimulator";185 break;186 case iPhoneOS:187 name = "iphoneos";188 break;189 case AppleTVSimulator:190 name = "appletvsimulator";191 break;192 case AppleTVOS:193 name = "appletvos";194 break;195 case WatchSimulator:196 name = "watchsimulator";197 break;198 case watchOS:199 name = "watchos";200 break;201 case XRSimulator:202 name = "xrsimulator";203 break;204 case XROS:205 name = "xros";206 break;207 case BridgeOS:208 name = "bridgeos";209 break;210 case Linux:211 name = "linux";212 break;213 case unknown:214 return {};215 }216 if (!info.version.empty())217 name += info.version.getAsString();218 if (info.internal)219 name += ".internal";220 return name;221}222 223bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,224 llvm::VersionTuple version) {225 switch (sdk_type) {226 case Type::MacOSX:227 return version >= llvm::VersionTuple(10, 10);228 case Type::iPhoneOS:229 case Type::iPhoneSimulator:230 case Type::AppleTVOS:231 case Type::AppleTVSimulator:232 return version >= llvm::VersionTuple(8);233 case Type::watchOS:234 case Type::WatchSimulator:235 return version >= llvm::VersionTuple(6);236 case Type::XROS:237 case Type::XRSimulator:238 return true;239 default:240 return false;241 }242 243 return false;244}245 246bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,247 const FileSpec &sdk_path) {248 ConstString last_path_component = sdk_path.GetFilename();249 250 if (!last_path_component)251 return false;252 253 XcodeSDK sdk(last_path_component.GetStringRef().str());254 if (sdk.GetType() != desired_type)255 return false;256 return SDKSupportsModules(sdk.GetType(), sdk.GetVersion());257}258 259XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) {260 using namespace llvm;261 switch (triple.getOS()) {262 case Triple::MacOSX:263 case Triple::Darwin:264 return XcodeSDK::MacOSX;265 case Triple::IOS:266 switch (triple.getEnvironment()) {267 case Triple::MacABI:268 return XcodeSDK::MacOSX;269 case Triple::Simulator:270 return XcodeSDK::iPhoneSimulator;271 default:272 return XcodeSDK::iPhoneOS;273 }274 case Triple::TvOS:275 if (triple.getEnvironment() == Triple::Simulator)276 return XcodeSDK::AppleTVSimulator;277 return XcodeSDK::AppleTVOS;278 case Triple::WatchOS:279 if (triple.getEnvironment() == Triple::Simulator)280 return XcodeSDK::WatchSimulator;281 return XcodeSDK::watchOS;282 case Triple::XROS:283 if (triple.getEnvironment() == Triple::Simulator)284 return XcodeSDK::XRSimulator;285 return XcodeSDK::XROS;286 case Triple::Linux:287 return XcodeSDK::Linux;288 default:289 return XcodeSDK::unknown;290 }291}292 293std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) {294 auto begin = llvm::sys::path::begin(path);295 auto end = llvm::sys::path::end(path);296 297 // Iterate over the path components until we find something that ends with298 // .app. If the next component is Contents then we've found the Contents299 // directory.300 for (auto it = begin; it != end; ++it) {301 if (it->ends_with(".app")) {302 auto next = it;303 if (++next != end && *next == "Contents") {304 llvm::SmallString<128> buffer;305 llvm::sys::path::append(buffer, begin, ++next,306 llvm::sys::path::Style::posix);307 return buffer.str().str();308 }309 }310 }311 312 return {};313}314