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