xref: /openbsd-src/gnu/llvm/lldb/source/Utility/XcodeSDK.cpp (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1dda28197Spatrick //===-- XcodeSDK.cpp ------------------------------------------------------===//
2dda28197Spatrick //
3dda28197Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4dda28197Spatrick // See https://llvm.org/LICENSE.txt for license information.
5dda28197Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dda28197Spatrick //
7dda28197Spatrick //===----------------------------------------------------------------------===//
8dda28197Spatrick 
9dda28197Spatrick #include "lldb/Utility/XcodeSDK.h"
10dda28197Spatrick #include "lldb/Utility/FileSpec.h"
11dda28197Spatrick 
12dda28197Spatrick #include "lldb/lldb-types.h"
13dda28197Spatrick 
14dda28197Spatrick #include "llvm/ADT/Triple.h"
15dda28197Spatrick 
16dda28197Spatrick #include <string>
17dda28197Spatrick 
18dda28197Spatrick using namespace lldb;
19dda28197Spatrick using namespace lldb_private;
20dda28197Spatrick 
21dda28197Spatrick static llvm::StringRef GetName(XcodeSDK::Type type) {
22dda28197Spatrick   switch (type) {
23dda28197Spatrick   case XcodeSDK::MacOSX:
24dda28197Spatrick     return "MacOSX";
25dda28197Spatrick   case XcodeSDK::iPhoneSimulator:
26dda28197Spatrick     return "iPhoneSimulator";
27dda28197Spatrick   case XcodeSDK::iPhoneOS:
28dda28197Spatrick     return "iPhoneOS";
29dda28197Spatrick   case XcodeSDK::AppleTVSimulator:
30dda28197Spatrick     return "AppleTVSimulator";
31dda28197Spatrick   case XcodeSDK::AppleTVOS:
32dda28197Spatrick     return "AppleTVOS";
33dda28197Spatrick   case XcodeSDK::WatchSimulator:
34dda28197Spatrick     return "WatchSimulator";
35dda28197Spatrick   case XcodeSDK::watchOS:
36dda28197Spatrick     return "WatchOS";
37dda28197Spatrick   case XcodeSDK::bridgeOS:
38dda28197Spatrick     return "bridgeOS";
39dda28197Spatrick   case XcodeSDK::Linux:
40dda28197Spatrick     return "Linux";
41dda28197Spatrick   case XcodeSDK::unknown:
42dda28197Spatrick     return {};
43dda28197Spatrick   }
44dda28197Spatrick   llvm_unreachable("Unhandled sdk type!");
45dda28197Spatrick }
46dda28197Spatrick 
47dda28197Spatrick XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) {
48dda28197Spatrick   if (!m_name.empty()) {
49dda28197Spatrick     if (!info.version.empty())
50dda28197Spatrick       m_name += info.version.getAsString();
51dda28197Spatrick     if (info.internal)
52dda28197Spatrick       m_name += ".Internal";
53dda28197Spatrick     m_name += ".sdk";
54dda28197Spatrick   }
55dda28197Spatrick }
56dda28197Spatrick 
57*be691f3bSpatrick XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) {
58dda28197Spatrick   m_name = other.m_name;
59dda28197Spatrick   return *this;
60dda28197Spatrick }
61dda28197Spatrick 
62*be691f3bSpatrick bool XcodeSDK::operator==(const XcodeSDK &other) {
63dda28197Spatrick   return m_name == other.m_name;
64dda28197Spatrick }
65dda28197Spatrick 
66dda28197Spatrick static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
67dda28197Spatrick   if (name.consume_front("MacOSX"))
68dda28197Spatrick     return XcodeSDK::MacOSX;
69dda28197Spatrick   if (name.consume_front("iPhoneSimulator"))
70dda28197Spatrick     return XcodeSDK::iPhoneSimulator;
71dda28197Spatrick   if (name.consume_front("iPhoneOS"))
72dda28197Spatrick     return XcodeSDK::iPhoneOS;
73dda28197Spatrick   if (name.consume_front("AppleTVSimulator"))
74dda28197Spatrick     return XcodeSDK::AppleTVSimulator;
75dda28197Spatrick   if (name.consume_front("AppleTVOS"))
76dda28197Spatrick     return XcodeSDK::AppleTVOS;
77dda28197Spatrick   if (name.consume_front("WatchSimulator"))
78dda28197Spatrick     return XcodeSDK::WatchSimulator;
79dda28197Spatrick   if (name.consume_front("WatchOS"))
80dda28197Spatrick     return XcodeSDK::watchOS;
81dda28197Spatrick   if (name.consume_front("bridgeOS"))
82dda28197Spatrick     return XcodeSDK::bridgeOS;
83dda28197Spatrick   if (name.consume_front("Linux"))
84dda28197Spatrick     return XcodeSDK::Linux;
85dda28197Spatrick   static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
86dda28197Spatrick                 "New SDK type was added, update this list!");
87dda28197Spatrick   return XcodeSDK::unknown;
88dda28197Spatrick }
89dda28197Spatrick 
90dda28197Spatrick static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
91dda28197Spatrick   unsigned i = 0;
92dda28197Spatrick   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
93dda28197Spatrick     ++i;
94dda28197Spatrick   if (i == name.size() || name[i++] != '.')
95dda28197Spatrick     return {};
96dda28197Spatrick   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
97dda28197Spatrick     ++i;
98dda28197Spatrick   if (i == name.size() || name[i++] != '.')
99dda28197Spatrick     return {};
100dda28197Spatrick 
101dda28197Spatrick   llvm::VersionTuple version;
102dda28197Spatrick   version.tryParse(name.slice(0, i - 1));
103dda28197Spatrick   name = name.drop_front(i);
104dda28197Spatrick   return version;
105dda28197Spatrick }
106dda28197Spatrick 
107dda28197Spatrick static bool ParseAppleInternalSDK(llvm::StringRef &name) {
108dda28197Spatrick   return name.consume_front("Internal.") || name.consume_front(".Internal.");
109dda28197Spatrick }
110dda28197Spatrick 
111dda28197Spatrick XcodeSDK::Info XcodeSDK::Parse() const {
112dda28197Spatrick   XcodeSDK::Info info;
113dda28197Spatrick   llvm::StringRef input(m_name);
114dda28197Spatrick   info.type = ParseSDKName(input);
115dda28197Spatrick   info.version = ParseSDKVersion(input);
116dda28197Spatrick   info.internal = ParseAppleInternalSDK(input);
117dda28197Spatrick   return info;
118dda28197Spatrick }
119dda28197Spatrick 
120dda28197Spatrick bool XcodeSDK::IsAppleInternalSDK() const {
121dda28197Spatrick   llvm::StringRef input(m_name);
122dda28197Spatrick   ParseSDKName(input);
123dda28197Spatrick   ParseSDKVersion(input);
124dda28197Spatrick   return ParseAppleInternalSDK(input);
125dda28197Spatrick }
126dda28197Spatrick 
127dda28197Spatrick llvm::VersionTuple XcodeSDK::GetVersion() const {
128dda28197Spatrick   llvm::StringRef input(m_name);
129dda28197Spatrick   ParseSDKName(input);
130dda28197Spatrick   return ParseSDKVersion(input);
131dda28197Spatrick }
132dda28197Spatrick 
133dda28197Spatrick XcodeSDK::Type XcodeSDK::GetType() const {
134dda28197Spatrick   llvm::StringRef input(m_name);
135dda28197Spatrick   return ParseSDKName(input);
136dda28197Spatrick }
137dda28197Spatrick 
138dda28197Spatrick llvm::StringRef XcodeSDK::GetString() const { return m_name; }
139dda28197Spatrick 
140dda28197Spatrick bool XcodeSDK::Info::operator<(const Info &other) const {
141dda28197Spatrick   return std::tie(type, version, internal) <
142dda28197Spatrick          std::tie(other.type, other.version, other.internal);
143dda28197Spatrick }
144dda28197Spatrick 
145dda28197Spatrick bool XcodeSDK::Info::operator==(const Info &other) const {
146dda28197Spatrick   return std::tie(type, version, internal) ==
147dda28197Spatrick          std::tie(other.type, other.version, other.internal);
148dda28197Spatrick }
149dda28197Spatrick 
150*be691f3bSpatrick void XcodeSDK::Merge(const XcodeSDK &other) {
151dda28197Spatrick   // The "bigger" SDK always wins.
152dda28197Spatrick   auto l = Parse();
153dda28197Spatrick   auto r = other.Parse();
154dda28197Spatrick   if (l < r)
155dda28197Spatrick     *this = other;
156dda28197Spatrick   else {
157dda28197Spatrick     // The Internal flag always wins.
158dda28197Spatrick     if (llvm::StringRef(m_name).endswith(".sdk"))
159dda28197Spatrick       if (!l.internal && r.internal)
160dda28197Spatrick         m_name =
161dda28197Spatrick             m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
162dda28197Spatrick   }
163dda28197Spatrick }
164dda28197Spatrick 
165dda28197Spatrick std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
166dda28197Spatrick   std::string name;
167dda28197Spatrick   switch (info.type) {
168dda28197Spatrick   case MacOSX:
169dda28197Spatrick     name = "macosx";
170dda28197Spatrick     break;
171dda28197Spatrick   case iPhoneSimulator:
172dda28197Spatrick     name = "iphonesimulator";
173dda28197Spatrick     break;
174dda28197Spatrick   case iPhoneOS:
175dda28197Spatrick     name = "iphoneos";
176dda28197Spatrick     break;
177dda28197Spatrick   case AppleTVSimulator:
178dda28197Spatrick     name = "appletvsimulator";
179dda28197Spatrick     break;
180dda28197Spatrick   case AppleTVOS:
181dda28197Spatrick     name = "appletvos";
182dda28197Spatrick     break;
183dda28197Spatrick   case WatchSimulator:
184dda28197Spatrick     name = "watchsimulator";
185dda28197Spatrick     break;
186dda28197Spatrick   case watchOS:
187dda28197Spatrick     name = "watchos";
188dda28197Spatrick     break;
189dda28197Spatrick   case bridgeOS:
190dda28197Spatrick     name = "bridgeos";
191dda28197Spatrick     break;
192dda28197Spatrick   case Linux:
193dda28197Spatrick     name = "linux";
194dda28197Spatrick     break;
195dda28197Spatrick   case unknown:
196dda28197Spatrick     return {};
197dda28197Spatrick   }
198dda28197Spatrick   if (!info.version.empty())
199dda28197Spatrick     name += info.version.getAsString();
200dda28197Spatrick   if (info.internal)
201dda28197Spatrick     name += ".internal";
202dda28197Spatrick   return name;
203dda28197Spatrick }
204dda28197Spatrick 
205dda28197Spatrick bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
206dda28197Spatrick                                   llvm::VersionTuple version) {
207dda28197Spatrick   switch (sdk_type) {
208dda28197Spatrick   case Type::MacOSX:
209dda28197Spatrick     return version >= llvm::VersionTuple(10, 10);
210dda28197Spatrick   case Type::iPhoneOS:
211dda28197Spatrick   case Type::iPhoneSimulator:
212dda28197Spatrick   case Type::AppleTVOS:
213dda28197Spatrick   case Type::AppleTVSimulator:
214dda28197Spatrick     return version >= llvm::VersionTuple(8);
215dda28197Spatrick   case Type::watchOS:
216dda28197Spatrick   case Type::WatchSimulator:
217dda28197Spatrick     return version >= llvm::VersionTuple(6);
218dda28197Spatrick   default:
219dda28197Spatrick     return false;
220dda28197Spatrick   }
221dda28197Spatrick 
222dda28197Spatrick   return false;
223dda28197Spatrick }
224dda28197Spatrick 
225dda28197Spatrick bool XcodeSDK::SupportsSwift() const {
226dda28197Spatrick   XcodeSDK::Info info = Parse();
227dda28197Spatrick   switch (info.type) {
228dda28197Spatrick   case Type::MacOSX:
229dda28197Spatrick     return info.version.empty() || info.version >= llvm::VersionTuple(10, 10);
230dda28197Spatrick   case Type::iPhoneOS:
231dda28197Spatrick   case Type::iPhoneSimulator:
232dda28197Spatrick     return info.version.empty() || info.version >= llvm::VersionTuple(8);
233dda28197Spatrick   case Type::AppleTVSimulator:
234dda28197Spatrick   case Type::AppleTVOS:
235dda28197Spatrick     return info.version.empty() || info.version >= llvm::VersionTuple(9);
236dda28197Spatrick   case Type::WatchSimulator:
237dda28197Spatrick   case Type::watchOS:
238dda28197Spatrick     return info.version.empty() || info.version >= llvm::VersionTuple(2);
239dda28197Spatrick   case Type::Linux:
240dda28197Spatrick     return true;
241dda28197Spatrick   default:
242dda28197Spatrick     return false;
243dda28197Spatrick   }
244dda28197Spatrick }
245dda28197Spatrick 
246dda28197Spatrick bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
247dda28197Spatrick                                   const FileSpec &sdk_path) {
248dda28197Spatrick   ConstString last_path_component = sdk_path.GetLastPathComponent();
249dda28197Spatrick 
250dda28197Spatrick   if (!last_path_component)
251dda28197Spatrick     return false;
252dda28197Spatrick 
253dda28197Spatrick   XcodeSDK sdk(last_path_component.GetStringRef().str());
254dda28197Spatrick   if (sdk.GetType() != desired_type)
255dda28197Spatrick     return false;
256dda28197Spatrick   return SDKSupportsModules(sdk.GetType(), sdk.GetVersion());
257dda28197Spatrick }
258dda28197Spatrick 
259dda28197Spatrick XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) {
260dda28197Spatrick   using namespace llvm;
261dda28197Spatrick   switch (triple.getOS()) {
262dda28197Spatrick   case Triple::MacOSX:
263dda28197Spatrick   case Triple::Darwin:
264dda28197Spatrick     return XcodeSDK::MacOSX;
265dda28197Spatrick   case Triple::IOS:
266dda28197Spatrick     switch (triple.getEnvironment()) {
267dda28197Spatrick     case Triple::MacABI:
268dda28197Spatrick       return XcodeSDK::MacOSX;
269dda28197Spatrick     case Triple::Simulator:
270dda28197Spatrick       return XcodeSDK::iPhoneSimulator;
271dda28197Spatrick     default:
272dda28197Spatrick       return XcodeSDK::iPhoneOS;
273dda28197Spatrick     }
274dda28197Spatrick   case Triple::TvOS:
275dda28197Spatrick     if (triple.getEnvironment() == Triple::Simulator)
276dda28197Spatrick       return XcodeSDK::AppleTVSimulator;
277dda28197Spatrick     return XcodeSDK::AppleTVOS;
278dda28197Spatrick   case Triple::WatchOS:
279dda28197Spatrick     if (triple.getEnvironment() == Triple::Simulator)
280dda28197Spatrick       return XcodeSDK::WatchSimulator;
281dda28197Spatrick     return XcodeSDK::watchOS;
282dda28197Spatrick   case Triple::Linux:
283dda28197Spatrick     return XcodeSDK::Linux;
284dda28197Spatrick   default:
285dda28197Spatrick     return XcodeSDK::unknown;
286dda28197Spatrick   }
287dda28197Spatrick }
288dda28197Spatrick 
289dda28197Spatrick std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) {
290dda28197Spatrick   auto begin = llvm::sys::path::begin(path);
291dda28197Spatrick   auto end = llvm::sys::path::end(path);
292dda28197Spatrick 
293dda28197Spatrick   // Iterate over the path components until we find something that ends with
294dda28197Spatrick   // .app. If the next component is Contents then we've found the Contents
295dda28197Spatrick   // directory.
296dda28197Spatrick   for (auto it = begin; it != end; ++it) {
297dda28197Spatrick     if (it->endswith(".app")) {
298dda28197Spatrick       auto next = it;
299dda28197Spatrick       if (++next != end && *next == "Contents") {
300dda28197Spatrick         llvm::SmallString<128> buffer;
301dda28197Spatrick         llvm::sys::path::append(buffer, begin, ++next,
302dda28197Spatrick                                 llvm::sys::path::Style::posix);
303dda28197Spatrick         return buffer.str().str();
304dda28197Spatrick       }
305dda28197Spatrick     }
306dda28197Spatrick   }
307dda28197Spatrick 
308dda28197Spatrick   return {};
309dda28197Spatrick }
310