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