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
GetName(XcodeSDK::Type type)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
XcodeSDK(XcodeSDK::Info info)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*f6aab3d8Srobert XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) = default;
58dda28197Spatrick
operator ==(const XcodeSDK & other)59be691f3bSpatrick bool XcodeSDK::operator==(const XcodeSDK &other) {
60dda28197Spatrick return m_name == other.m_name;
61dda28197Spatrick }
62dda28197Spatrick
ParseSDKName(llvm::StringRef & name)63dda28197Spatrick static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
64dda28197Spatrick if (name.consume_front("MacOSX"))
65dda28197Spatrick return XcodeSDK::MacOSX;
66dda28197Spatrick if (name.consume_front("iPhoneSimulator"))
67dda28197Spatrick return XcodeSDK::iPhoneSimulator;
68dda28197Spatrick if (name.consume_front("iPhoneOS"))
69dda28197Spatrick return XcodeSDK::iPhoneOS;
70dda28197Spatrick if (name.consume_front("AppleTVSimulator"))
71dda28197Spatrick return XcodeSDK::AppleTVSimulator;
72dda28197Spatrick if (name.consume_front("AppleTVOS"))
73dda28197Spatrick return XcodeSDK::AppleTVOS;
74dda28197Spatrick if (name.consume_front("WatchSimulator"))
75dda28197Spatrick return XcodeSDK::WatchSimulator;
76dda28197Spatrick if (name.consume_front("WatchOS"))
77dda28197Spatrick return XcodeSDK::watchOS;
78dda28197Spatrick if (name.consume_front("bridgeOS"))
79dda28197Spatrick return XcodeSDK::bridgeOS;
80dda28197Spatrick if (name.consume_front("Linux"))
81dda28197Spatrick return XcodeSDK::Linux;
82dda28197Spatrick static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
83dda28197Spatrick "New SDK type was added, update this list!");
84dda28197Spatrick return XcodeSDK::unknown;
85dda28197Spatrick }
86dda28197Spatrick
ParseSDKVersion(llvm::StringRef & name)87dda28197Spatrick static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
88dda28197Spatrick unsigned i = 0;
89dda28197Spatrick while (i < name.size() && name[i] >= '0' && name[i] <= '9')
90dda28197Spatrick ++i;
91dda28197Spatrick if (i == name.size() || name[i++] != '.')
92dda28197Spatrick return {};
93dda28197Spatrick while (i < name.size() && name[i] >= '0' && name[i] <= '9')
94dda28197Spatrick ++i;
95dda28197Spatrick if (i == name.size() || name[i++] != '.')
96dda28197Spatrick return {};
97dda28197Spatrick
98dda28197Spatrick llvm::VersionTuple version;
99dda28197Spatrick version.tryParse(name.slice(0, i - 1));
100dda28197Spatrick name = name.drop_front(i);
101dda28197Spatrick return version;
102dda28197Spatrick }
103dda28197Spatrick
ParseAppleInternalSDK(llvm::StringRef & name)104dda28197Spatrick static bool ParseAppleInternalSDK(llvm::StringRef &name) {
105dda28197Spatrick return name.consume_front("Internal.") || name.consume_front(".Internal.");
106dda28197Spatrick }
107dda28197Spatrick
Parse() const108dda28197Spatrick XcodeSDK::Info XcodeSDK::Parse() const {
109dda28197Spatrick XcodeSDK::Info info;
110dda28197Spatrick llvm::StringRef input(m_name);
111dda28197Spatrick info.type = ParseSDKName(input);
112dda28197Spatrick info.version = ParseSDKVersion(input);
113dda28197Spatrick info.internal = ParseAppleInternalSDK(input);
114dda28197Spatrick return info;
115dda28197Spatrick }
116dda28197Spatrick
IsAppleInternalSDK() const117dda28197Spatrick bool XcodeSDK::IsAppleInternalSDK() const {
118dda28197Spatrick llvm::StringRef input(m_name);
119dda28197Spatrick ParseSDKName(input);
120dda28197Spatrick ParseSDKVersion(input);
121dda28197Spatrick return ParseAppleInternalSDK(input);
122dda28197Spatrick }
123dda28197Spatrick
GetVersion() const124dda28197Spatrick llvm::VersionTuple XcodeSDK::GetVersion() const {
125dda28197Spatrick llvm::StringRef input(m_name);
126dda28197Spatrick ParseSDKName(input);
127dda28197Spatrick return ParseSDKVersion(input);
128dda28197Spatrick }
129dda28197Spatrick
GetType() const130dda28197Spatrick XcodeSDK::Type XcodeSDK::GetType() const {
131dda28197Spatrick llvm::StringRef input(m_name);
132dda28197Spatrick return ParseSDKName(input);
133dda28197Spatrick }
134dda28197Spatrick
GetString() const135dda28197Spatrick llvm::StringRef XcodeSDK::GetString() const { return m_name; }
136dda28197Spatrick
operator <(const Info & other) const137dda28197Spatrick bool XcodeSDK::Info::operator<(const Info &other) const {
138dda28197Spatrick return std::tie(type, version, internal) <
139dda28197Spatrick std::tie(other.type, other.version, other.internal);
140dda28197Spatrick }
141dda28197Spatrick
operator ==(const Info & other) const142dda28197Spatrick bool XcodeSDK::Info::operator==(const Info &other) const {
143dda28197Spatrick return std::tie(type, version, internal) ==
144dda28197Spatrick std::tie(other.type, other.version, other.internal);
145dda28197Spatrick }
146dda28197Spatrick
Merge(const XcodeSDK & other)147be691f3bSpatrick void XcodeSDK::Merge(const XcodeSDK &other) {
148dda28197Spatrick // The "bigger" SDK always wins.
149dda28197Spatrick auto l = Parse();
150dda28197Spatrick auto r = other.Parse();
151dda28197Spatrick if (l < r)
152dda28197Spatrick *this = other;
153dda28197Spatrick else {
154dda28197Spatrick // The Internal flag always wins.
155dda28197Spatrick if (llvm::StringRef(m_name).endswith(".sdk"))
156dda28197Spatrick if (!l.internal && r.internal)
157dda28197Spatrick m_name =
158dda28197Spatrick m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
159dda28197Spatrick }
160dda28197Spatrick }
161dda28197Spatrick
GetCanonicalName(XcodeSDK::Info info)162dda28197Spatrick std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
163dda28197Spatrick std::string name;
164dda28197Spatrick switch (info.type) {
165dda28197Spatrick case MacOSX:
166dda28197Spatrick name = "macosx";
167dda28197Spatrick break;
168dda28197Spatrick case iPhoneSimulator:
169dda28197Spatrick name = "iphonesimulator";
170dda28197Spatrick break;
171dda28197Spatrick case iPhoneOS:
172dda28197Spatrick name = "iphoneos";
173dda28197Spatrick break;
174dda28197Spatrick case AppleTVSimulator:
175dda28197Spatrick name = "appletvsimulator";
176dda28197Spatrick break;
177dda28197Spatrick case AppleTVOS:
178dda28197Spatrick name = "appletvos";
179dda28197Spatrick break;
180dda28197Spatrick case WatchSimulator:
181dda28197Spatrick name = "watchsimulator";
182dda28197Spatrick break;
183dda28197Spatrick case watchOS:
184dda28197Spatrick name = "watchos";
185dda28197Spatrick break;
186dda28197Spatrick case bridgeOS:
187dda28197Spatrick name = "bridgeos";
188dda28197Spatrick break;
189dda28197Spatrick case Linux:
190dda28197Spatrick name = "linux";
191dda28197Spatrick break;
192dda28197Spatrick case unknown:
193dda28197Spatrick return {};
194dda28197Spatrick }
195dda28197Spatrick if (!info.version.empty())
196dda28197Spatrick name += info.version.getAsString();
197dda28197Spatrick if (info.internal)
198dda28197Spatrick name += ".internal";
199dda28197Spatrick return name;
200dda28197Spatrick }
201dda28197Spatrick
SDKSupportsModules(XcodeSDK::Type sdk_type,llvm::VersionTuple version)202dda28197Spatrick bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
203dda28197Spatrick llvm::VersionTuple version) {
204dda28197Spatrick switch (sdk_type) {
205dda28197Spatrick case Type::MacOSX:
206dda28197Spatrick return version >= llvm::VersionTuple(10, 10);
207dda28197Spatrick case Type::iPhoneOS:
208dda28197Spatrick case Type::iPhoneSimulator:
209dda28197Spatrick case Type::AppleTVOS:
210dda28197Spatrick case Type::AppleTVSimulator:
211dda28197Spatrick return version >= llvm::VersionTuple(8);
212dda28197Spatrick case Type::watchOS:
213dda28197Spatrick case Type::WatchSimulator:
214dda28197Spatrick return version >= llvm::VersionTuple(6);
215dda28197Spatrick default:
216dda28197Spatrick return false;
217dda28197Spatrick }
218dda28197Spatrick
219dda28197Spatrick return false;
220dda28197Spatrick }
221dda28197Spatrick
SupportsSwift() const222dda28197Spatrick bool XcodeSDK::SupportsSwift() const {
223dda28197Spatrick XcodeSDK::Info info = Parse();
224dda28197Spatrick switch (info.type) {
225dda28197Spatrick case Type::MacOSX:
226dda28197Spatrick return info.version.empty() || info.version >= llvm::VersionTuple(10, 10);
227dda28197Spatrick case Type::iPhoneOS:
228dda28197Spatrick case Type::iPhoneSimulator:
229dda28197Spatrick return info.version.empty() || info.version >= llvm::VersionTuple(8);
230dda28197Spatrick case Type::AppleTVSimulator:
231dda28197Spatrick case Type::AppleTVOS:
232dda28197Spatrick return info.version.empty() || info.version >= llvm::VersionTuple(9);
233dda28197Spatrick case Type::WatchSimulator:
234dda28197Spatrick case Type::watchOS:
235dda28197Spatrick return info.version.empty() || info.version >= llvm::VersionTuple(2);
236dda28197Spatrick case Type::Linux:
237dda28197Spatrick return true;
238dda28197Spatrick default:
239dda28197Spatrick return false;
240dda28197Spatrick }
241dda28197Spatrick }
242dda28197Spatrick
SDKSupportsModules(XcodeSDK::Type desired_type,const FileSpec & sdk_path)243dda28197Spatrick bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
244dda28197Spatrick const FileSpec &sdk_path) {
245dda28197Spatrick ConstString last_path_component = sdk_path.GetLastPathComponent();
246dda28197Spatrick
247dda28197Spatrick if (!last_path_component)
248dda28197Spatrick return false;
249dda28197Spatrick
250dda28197Spatrick XcodeSDK sdk(last_path_component.GetStringRef().str());
251dda28197Spatrick if (sdk.GetType() != desired_type)
252dda28197Spatrick return false;
253dda28197Spatrick return SDKSupportsModules(sdk.GetType(), sdk.GetVersion());
254dda28197Spatrick }
255dda28197Spatrick
GetSDKTypeForTriple(const llvm::Triple & triple)256dda28197Spatrick XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) {
257dda28197Spatrick using namespace llvm;
258dda28197Spatrick switch (triple.getOS()) {
259dda28197Spatrick case Triple::MacOSX:
260dda28197Spatrick case Triple::Darwin:
261dda28197Spatrick return XcodeSDK::MacOSX;
262dda28197Spatrick case Triple::IOS:
263dda28197Spatrick switch (triple.getEnvironment()) {
264dda28197Spatrick case Triple::MacABI:
265dda28197Spatrick return XcodeSDK::MacOSX;
266dda28197Spatrick case Triple::Simulator:
267dda28197Spatrick return XcodeSDK::iPhoneSimulator;
268dda28197Spatrick default:
269dda28197Spatrick return XcodeSDK::iPhoneOS;
270dda28197Spatrick }
271dda28197Spatrick case Triple::TvOS:
272dda28197Spatrick if (triple.getEnvironment() == Triple::Simulator)
273dda28197Spatrick return XcodeSDK::AppleTVSimulator;
274dda28197Spatrick return XcodeSDK::AppleTVOS;
275dda28197Spatrick case Triple::WatchOS:
276dda28197Spatrick if (triple.getEnvironment() == Triple::Simulator)
277dda28197Spatrick return XcodeSDK::WatchSimulator;
278dda28197Spatrick return XcodeSDK::watchOS;
279dda28197Spatrick case Triple::Linux:
280dda28197Spatrick return XcodeSDK::Linux;
281dda28197Spatrick default:
282dda28197Spatrick return XcodeSDK::unknown;
283dda28197Spatrick }
284dda28197Spatrick }
285dda28197Spatrick
FindXcodeContentsDirectoryInPath(llvm::StringRef path)286dda28197Spatrick std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) {
287dda28197Spatrick auto begin = llvm::sys::path::begin(path);
288dda28197Spatrick auto end = llvm::sys::path::end(path);
289dda28197Spatrick
290dda28197Spatrick // Iterate over the path components until we find something that ends with
291dda28197Spatrick // .app. If the next component is Contents then we've found the Contents
292dda28197Spatrick // directory.
293dda28197Spatrick for (auto it = begin; it != end; ++it) {
294dda28197Spatrick if (it->endswith(".app")) {
295dda28197Spatrick auto next = it;
296dda28197Spatrick if (++next != end && *next == "Contents") {
297dda28197Spatrick llvm::SmallString<128> buffer;
298dda28197Spatrick llvm::sys::path::append(buffer, begin, ++next,
299dda28197Spatrick llvm::sys::path::Style::posix);
300dda28197Spatrick return buffer.str().str();
301dda28197Spatrick }
302dda28197Spatrick }
303dda28197Spatrick }
304dda28197Spatrick
305dda28197Spatrick return {};
306dda28197Spatrick }
307