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-exception 6 // 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/ADT/Triple.h" 15 16 #include <string> 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 static 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::bridgeOS: 38 return "bridgeOS"; 39 case XcodeSDK::Linux: 40 return "Linux"; 41 case XcodeSDK::unknown: 42 return {}; 43 } 44 } 45 46 XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) { 47 if (!m_name.empty()) { 48 if (!info.version.empty()) 49 m_name += info.version.getAsString(); 50 if (info.internal) 51 m_name += ".Internal"; 52 m_name += ".sdk"; 53 } 54 } 55 56 XcodeSDK &XcodeSDK::operator=(XcodeSDK other) { 57 m_name = other.m_name; 58 return *this; 59 } 60 61 bool XcodeSDK::operator==(XcodeSDK other) { 62 return m_name == other.m_name; 63 } 64 65 static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) { 66 if (name.consume_front("MacOSX")) 67 return XcodeSDK::MacOSX; 68 if (name.consume_front("iPhoneSimulator")) 69 return XcodeSDK::iPhoneSimulator; 70 if (name.consume_front("iPhoneOS")) 71 return XcodeSDK::iPhoneOS; 72 if (name.consume_front("AppleTVSimulator")) 73 return XcodeSDK::AppleTVSimulator; 74 if (name.consume_front("AppleTVOS")) 75 return XcodeSDK::AppleTVOS; 76 if (name.consume_front("WatchSimulator")) 77 return XcodeSDK::WatchSimulator; 78 if (name.consume_front("WatchOS")) 79 return XcodeSDK::watchOS; 80 if (name.consume_front("bridgeOS")) 81 return XcodeSDK::bridgeOS; 82 if (name.consume_front("Linux")) 83 return XcodeSDK::Linux; 84 static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1, 85 "New SDK type was added, update this list!"); 86 return XcodeSDK::unknown; 87 } 88 89 static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) { 90 unsigned i = 0; 91 while (i < name.size() && name[i] >= '0' && name[i] <= '9') 92 ++i; 93 if (i == name.size() || name[i++] != '.') 94 return {}; 95 while (i < name.size() && name[i] >= '0' && name[i] <= '9') 96 ++i; 97 if (i == name.size() || name[i++] != '.') 98 return {}; 99 100 llvm::VersionTuple version; 101 version.tryParse(name.slice(0, i - 1)); 102 name = name.drop_front(i); 103 return version; 104 } 105 106 static bool ParseAppleInternalSDK(llvm::StringRef &name) { 107 return name.consume_front("Internal.") || name.consume_front(".Internal."); 108 } 109 110 XcodeSDK::Info XcodeSDK::Parse() const { 111 XcodeSDK::Info info; 112 llvm::StringRef input(m_name); 113 info.type = ParseSDKName(input); 114 info.version = ParseSDKVersion(input); 115 info.internal = ParseAppleInternalSDK(input); 116 return info; 117 } 118 119 bool XcodeSDK::IsAppleInternalSDK() const { 120 llvm::StringRef input(m_name); 121 ParseSDKName(input); 122 ParseSDKVersion(input); 123 return ParseAppleInternalSDK(input); 124 } 125 126 llvm::VersionTuple XcodeSDK::GetVersion() const { 127 llvm::StringRef input(m_name); 128 ParseSDKName(input); 129 return ParseSDKVersion(input); 130 } 131 132 XcodeSDK::Type XcodeSDK::GetType() const { 133 llvm::StringRef input(m_name); 134 return ParseSDKName(input); 135 } 136 137 llvm::StringRef XcodeSDK::GetString() const { return m_name; } 138 139 bool XcodeSDK::Info::operator<(const Info &other) const { 140 return std::tie(type, version, internal) < 141 std::tie(other.type, other.version, other.internal); 142 } 143 144 bool XcodeSDK::Info::operator==(const Info &other) const { 145 return std::tie(type, version, internal) == 146 std::tie(other.type, other.version, other.internal); 147 } 148 149 void XcodeSDK::Merge(XcodeSDK other) { 150 // The "bigger" SDK always wins. 151 auto l = Parse(); 152 auto r = other.Parse(); 153 if (l < r) 154 *this = other; 155 else { 156 // The Internal flag always wins. 157 if (llvm::StringRef(m_name).endswith(".sdk")) 158 if (!l.internal && r.internal) 159 m_name = 160 m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk"); 161 } 162 } 163 164 std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) { 165 std::string name; 166 switch (info.type) { 167 case MacOSX: 168 name = "macosx"; 169 break; 170 case iPhoneSimulator: 171 name = "iphonesimulator"; 172 break; 173 case iPhoneOS: 174 name = "iphoneos"; 175 break; 176 case AppleTVSimulator: 177 name = "appletvsimulator"; 178 break; 179 case AppleTVOS: 180 name = "appletvos"; 181 break; 182 case WatchSimulator: 183 name = "watchsimulator"; 184 break; 185 case watchOS: 186 name = "watchos"; 187 break; 188 case bridgeOS: 189 name = "bridgeos"; 190 break; 191 case Linux: 192 name = "linux"; 193 break; 194 case unknown: 195 return {}; 196 } 197 if (!info.version.empty()) 198 name += info.version.getAsString(); 199 if (info.internal) 200 name += ".internal"; 201 return name; 202 } 203 204 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, 205 llvm::VersionTuple version) { 206 switch (sdk_type) { 207 case Type::MacOSX: 208 return version >= llvm::VersionTuple(10, 10); 209 case Type::iPhoneOS: 210 case Type::iPhoneSimulator: 211 case Type::AppleTVOS: 212 case Type::AppleTVSimulator: 213 return version >= llvm::VersionTuple(8); 214 case Type::watchOS: 215 case Type::WatchSimulator: 216 return version >= llvm::VersionTuple(6); 217 default: 218 return false; 219 } 220 221 return false; 222 } 223 224 bool XcodeSDK::SupportsSwift() const { 225 XcodeSDK::Info info = Parse(); 226 switch (info.type) { 227 case Type::MacOSX: 228 return info.version.empty() || info.version >= llvm::VersionTuple(10, 10); 229 case Type::iPhoneOS: 230 case Type::iPhoneSimulator: 231 return info.version.empty() || info.version >= llvm::VersionTuple(8); 232 case Type::AppleTVSimulator: 233 case Type::AppleTVOS: 234 return info.version.empty() || info.version >= llvm::VersionTuple(9); 235 case Type::WatchSimulator: 236 case Type::watchOS: 237 return info.version.empty() || info.version >= llvm::VersionTuple(2); 238 case Type::Linux: 239 return true; 240 default: 241 return false; 242 } 243 } 244 245 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type, 246 const FileSpec &sdk_path) { 247 ConstString last_path_component = sdk_path.GetLastPathComponent(); 248 249 if (!last_path_component) 250 return false; 251 252 XcodeSDK sdk(last_path_component.GetStringRef().str()); 253 if (sdk.GetType() != desired_type) 254 return false; 255 return SDKSupportsModules(sdk.GetType(), sdk.GetVersion()); 256 } 257 258 XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) { 259 using namespace llvm; 260 switch (triple.getOS()) { 261 case Triple::MacOSX: 262 case Triple::Darwin: 263 return XcodeSDK::MacOSX; 264 case Triple::IOS: 265 switch (triple.getEnvironment()) { 266 case Triple::MacABI: 267 return XcodeSDK::MacOSX; 268 case Triple::Simulator: 269 return XcodeSDK::iPhoneSimulator; 270 default: 271 return XcodeSDK::iPhoneOS; 272 } 273 case Triple::TvOS: 274 if (triple.getEnvironment() == Triple::Simulator) 275 return XcodeSDK::AppleTVSimulator; 276 return XcodeSDK::AppleTVOS; 277 case Triple::WatchOS: 278 if (triple.getEnvironment() == Triple::Simulator) 279 return XcodeSDK::WatchSimulator; 280 return XcodeSDK::watchOS; 281 case Triple::Linux: 282 return XcodeSDK::Linux; 283 default: 284 return XcodeSDK::unknown; 285 } 286 } 287