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