xref: /freebsd/contrib/llvm-project/lldb/source/Utility/XcodeSDK.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/TargetParser/Triple.h"
15 
16 #include <string>
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
GetName(XcodeSDK::Type type)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::XRSimulator:
38     return "XRSimulator";
39   case XcodeSDK::XROS:
40     return "XROS";
41   case XcodeSDK::bridgeOS:
42     return "bridgeOS";
43   case XcodeSDK::Linux:
44     return "Linux";
45   case XcodeSDK::unknown:
46     return {};
47   }
48   llvm_unreachable("Unhandled sdk type!");
49 }
50 
XcodeSDK(XcodeSDK::Info info)51 XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) {
52   if (!m_name.empty()) {
53     if (!info.version.empty())
54       m_name += info.version.getAsString();
55     if (info.internal)
56       m_name += ".Internal";
57     m_name += ".sdk";
58   }
59 }
60 
61 XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) = default;
62 
operator ==(const XcodeSDK & other) const63 bool XcodeSDK::operator==(const XcodeSDK &other) const {
64   return m_name == other.m_name;
65 }
66 
ParseSDKName(llvm::StringRef & name)67 static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
68   if (name.consume_front("MacOSX"))
69     return XcodeSDK::MacOSX;
70   if (name.consume_front("iPhoneSimulator"))
71     return XcodeSDK::iPhoneSimulator;
72   if (name.consume_front("iPhoneOS"))
73     return XcodeSDK::iPhoneOS;
74   if (name.consume_front("AppleTVSimulator"))
75     return XcodeSDK::AppleTVSimulator;
76   if (name.consume_front("AppleTVOS"))
77     return XcodeSDK::AppleTVOS;
78   if (name.consume_front("WatchSimulator"))
79     return XcodeSDK::WatchSimulator;
80   if (name.consume_front("WatchOS"))
81     return XcodeSDK::watchOS;
82   if (name.consume_front("XRSimulator"))
83     return XcodeSDK::XRSimulator;
84   if (name.consume_front("XROS"))
85     return XcodeSDK::XROS;
86   if (name.consume_front("bridgeOS"))
87     return XcodeSDK::bridgeOS;
88   if (name.consume_front("Linux"))
89     return XcodeSDK::Linux;
90   static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
91                 "New SDK type was added, update this list!");
92   return XcodeSDK::unknown;
93 }
94 
ParseSDKVersion(llvm::StringRef & name)95 static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
96   unsigned i = 0;
97   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
98     ++i;
99   if (i == name.size() || name[i++] != '.')
100     return {};
101   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
102     ++i;
103   if (i == name.size() || name[i++] != '.')
104     return {};
105 
106   llvm::VersionTuple version;
107   version.tryParse(name.slice(0, i - 1));
108   name = name.drop_front(i);
109   return version;
110 }
111 
ParseAppleInternalSDK(llvm::StringRef & name)112 static bool ParseAppleInternalSDK(llvm::StringRef &name) {
113   return name.consume_front("Internal.") || name.consume_front(".Internal.");
114 }
115 
Parse() const116 XcodeSDK::Info XcodeSDK::Parse() const {
117   XcodeSDK::Info info;
118   llvm::StringRef input(m_name);
119   info.type = ParseSDKName(input);
120   info.version = ParseSDKVersion(input);
121   info.internal = ParseAppleInternalSDK(input);
122   return info;
123 }
124 
IsAppleInternalSDK() const125 bool XcodeSDK::IsAppleInternalSDK() const {
126   llvm::StringRef input(m_name);
127   ParseSDKName(input);
128   ParseSDKVersion(input);
129   return ParseAppleInternalSDK(input);
130 }
131 
GetVersion() const132 llvm::VersionTuple XcodeSDK::GetVersion() const {
133   llvm::StringRef input(m_name);
134   ParseSDKName(input);
135   return ParseSDKVersion(input);
136 }
137 
GetType() const138 XcodeSDK::Type XcodeSDK::GetType() const {
139   llvm::StringRef input(m_name);
140   return ParseSDKName(input);
141 }
142 
GetString() const143 llvm::StringRef XcodeSDK::GetString() const { return m_name; }
144 
GetSysroot() const145 const FileSpec &XcodeSDK::GetSysroot() const { return m_sysroot; }
146 
operator <(const Info & other) const147 bool XcodeSDK::Info::operator<(const Info &other) const {
148   return std::tie(type, version, internal) <
149          std::tie(other.type, other.version, other.internal);
150 }
151 
operator ==(const Info & other) const152 bool XcodeSDK::Info::operator==(const Info &other) const {
153   return std::tie(type, version, internal) ==
154          std::tie(other.type, other.version, other.internal);
155 }
156 
Merge(const XcodeSDK & other)157 void XcodeSDK::Merge(const XcodeSDK &other) {
158   // The "bigger" SDK always wins.
159   auto l = Parse();
160   auto r = other.Parse();
161   if (l < r)
162     *this = other;
163   else {
164     // The Internal flag always wins.
165     if (!l.internal && r.internal) {
166       if (llvm::StringRef(m_name).ends_with(".sdk"))
167         m_name =
168             m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
169     }
170   }
171 
172   // We changed the SDK name. Adjust the sysroot accordingly.
173   if (m_sysroot && m_sysroot.GetFilename().GetStringRef() != m_name)
174     m_sysroot.SetFilename(m_name);
175 }
176 
GetCanonicalName(XcodeSDK::Info info)177 std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
178   std::string name;
179   switch (info.type) {
180   case MacOSX:
181     name = "macosx";
182     break;
183   case iPhoneSimulator:
184     name = "iphonesimulator";
185     break;
186   case iPhoneOS:
187     name = "iphoneos";
188     break;
189   case AppleTVSimulator:
190     name = "appletvsimulator";
191     break;
192   case AppleTVOS:
193     name = "appletvos";
194     break;
195   case WatchSimulator:
196     name = "watchsimulator";
197     break;
198   case watchOS:
199     name = "watchos";
200     break;
201   case XRSimulator:
202     name = "xrsimulator";
203     break;
204   case XROS:
205     name = "xros";
206     break;
207   case bridgeOS:
208     name = "bridgeos";
209     break;
210   case Linux:
211     name = "linux";
212     break;
213   case unknown:
214     return {};
215   }
216   if (!info.version.empty())
217     name += info.version.getAsString();
218   if (info.internal)
219     name += ".internal";
220   return name;
221 }
222 
SDKSupportsModules(XcodeSDK::Type sdk_type,llvm::VersionTuple version)223 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
224                                   llvm::VersionTuple version) {
225   switch (sdk_type) {
226   case Type::MacOSX:
227     return version >= llvm::VersionTuple(10, 10);
228   case Type::iPhoneOS:
229   case Type::iPhoneSimulator:
230   case Type::AppleTVOS:
231   case Type::AppleTVSimulator:
232     return version >= llvm::VersionTuple(8);
233   case Type::watchOS:
234   case Type::WatchSimulator:
235     return version >= llvm::VersionTuple(6);
236   case Type::XROS:
237   case Type::XRSimulator:
238     return true;
239   default:
240     return false;
241   }
242 
243   return false;
244 }
245 
SupportsSwift() const246 bool XcodeSDK::SupportsSwift() const {
247   XcodeSDK::Info info = Parse();
248   switch (info.type) {
249   case Type::MacOSX:
250     return info.version.empty() || info.version >= llvm::VersionTuple(10, 10);
251   case Type::iPhoneOS:
252   case Type::iPhoneSimulator:
253     return info.version.empty() || info.version >= llvm::VersionTuple(8);
254   case Type::AppleTVSimulator:
255   case Type::AppleTVOS:
256     return info.version.empty() || info.version >= llvm::VersionTuple(9);
257   case Type::WatchSimulator:
258   case Type::watchOS:
259     return info.version.empty() || info.version >= llvm::VersionTuple(2);
260   case Type::XROS:
261   case Type::XRSimulator:
262   case Type::Linux:
263     return true;
264   default:
265     return false;
266   }
267 }
268 
SDKSupportsBuiltinModules(const llvm::Triple & target_triple,llvm::VersionTuple sdk_version)269 bool XcodeSDK::SDKSupportsBuiltinModules(const llvm::Triple &target_triple,
270                                          llvm::VersionTuple sdk_version) {
271   using namespace llvm;
272 
273   switch (target_triple.getOS()) {
274   case Triple::OSType::MacOSX:
275     return sdk_version >= VersionTuple(15U);
276   case Triple::OSType::IOS:
277     return sdk_version >= VersionTuple(18U);
278   case Triple::OSType::TvOS:
279     return sdk_version >= VersionTuple(18U);
280   case Triple::OSType::WatchOS:
281     return sdk_version >= VersionTuple(11U);
282   case Triple::OSType::XROS:
283     return sdk_version >= VersionTuple(2U);
284   default:
285     // New SDKs support builtin modules from the start.
286     return true;
287   }
288 }
289 
SDKSupportsModules(XcodeSDK::Type desired_type,const FileSpec & sdk_path)290 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
291                                   const FileSpec &sdk_path) {
292   ConstString last_path_component = sdk_path.GetFilename();
293 
294   if (!last_path_component)
295     return false;
296 
297   XcodeSDK sdk(last_path_component.GetStringRef().str());
298   if (sdk.GetType() != desired_type)
299     return false;
300   return SDKSupportsModules(sdk.GetType(), sdk.GetVersion());
301 }
302 
GetSDKTypeForTriple(const llvm::Triple & triple)303 XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) {
304   using namespace llvm;
305   switch (triple.getOS()) {
306   case Triple::MacOSX:
307   case Triple::Darwin:
308     return XcodeSDK::MacOSX;
309   case Triple::IOS:
310     switch (triple.getEnvironment()) {
311     case Triple::MacABI:
312       return XcodeSDK::MacOSX;
313     case Triple::Simulator:
314       return XcodeSDK::iPhoneSimulator;
315     default:
316       return XcodeSDK::iPhoneOS;
317     }
318   case Triple::TvOS:
319     if (triple.getEnvironment() == Triple::Simulator)
320       return XcodeSDK::AppleTVSimulator;
321     return XcodeSDK::AppleTVOS;
322   case Triple::WatchOS:
323     if (triple.getEnvironment() == Triple::Simulator)
324       return XcodeSDK::WatchSimulator;
325     return XcodeSDK::watchOS;
326   case Triple::XROS:
327     if (triple.getEnvironment() == Triple::Simulator)
328       return XcodeSDK::XRSimulator;
329     return XcodeSDK::XROS;
330   case Triple::Linux:
331     return XcodeSDK::Linux;
332   default:
333     return XcodeSDK::unknown;
334   }
335 }
336 
FindXcodeContentsDirectoryInPath(llvm::StringRef path)337 std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) {
338   auto begin = llvm::sys::path::begin(path);
339   auto end = llvm::sys::path::end(path);
340 
341   // Iterate over the path components until we find something that ends with
342   // .app. If the next component is Contents then we've found the Contents
343   // directory.
344   for (auto it = begin; it != end; ++it) {
345     if (it->ends_with(".app")) {
346       auto next = it;
347       if (++next != end && *next == "Contents") {
348         llvm::SmallString<128> buffer;
349         llvm::sys::path::append(buffer, begin, ++next,
350                                 llvm::sys::path::Style::posix);
351         return buffer.str().str();
352       }
353     }
354   }
355 
356   return {};
357 }
358