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