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