1 //===-- XcodeSDK.cpp ------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/XcodeSDK.h"
10 #include "lldb/Utility/FileSpec.h"
12 #include "lldb/lldb-types.h"
14 #include "llvm/ADT/Triple.h"
19 using namespace lldb_private
;
21 static llvm::StringRef
GetName(XcodeSDK::Type type
) {
23 case XcodeSDK::MacOSX
:
25 case XcodeSDK::iPhoneSimulator
:
26 return "iPhoneSimulator";
27 case XcodeSDK::iPhoneOS
:
29 case XcodeSDK::AppleTVSimulator
:
30 return "AppleTVSimulator";
31 case XcodeSDK::AppleTVOS
:
33 case XcodeSDK::WatchSimulator
:
34 return "WatchSimulator";
35 case XcodeSDK::watchOS
:
37 case XcodeSDK::bridgeOS
:
41 case XcodeSDK::unknown
:
44 llvm_unreachable("Unhandled sdk type!");
47 XcodeSDK::XcodeSDK(XcodeSDK::Info info
) : m_name(GetName(info
.type
).str()) {
48 if (!m_name
.empty()) {
49 if (!info
.version
.empty())
50 m_name
+= info
.version
.getAsString();
52 m_name
+= ".Internal";
57 XcodeSDK
&XcodeSDK::operator=(const XcodeSDK
&other
) {
58 m_name
= other
.m_name
;
62 bool XcodeSDK::operator==(const XcodeSDK
&other
) {
63 return m_name
== other
.m_name
;
66 static XcodeSDK::Type
ParseSDKName(llvm::StringRef
&name
) {
67 if (name
.consume_front("MacOSX"))
68 return XcodeSDK::MacOSX
;
69 if (name
.consume_front("iPhoneSimulator"))
70 return XcodeSDK::iPhoneSimulator
;
71 if (name
.consume_front("iPhoneOS"))
72 return XcodeSDK::iPhoneOS
;
73 if (name
.consume_front("AppleTVSimulator"))
74 return XcodeSDK::AppleTVSimulator
;
75 if (name
.consume_front("AppleTVOS"))
76 return XcodeSDK::AppleTVOS
;
77 if (name
.consume_front("WatchSimulator"))
78 return XcodeSDK::WatchSimulator
;
79 if (name
.consume_front("WatchOS"))
80 return XcodeSDK::watchOS
;
81 if (name
.consume_front("bridgeOS"))
82 return XcodeSDK::bridgeOS
;
83 if (name
.consume_front("Linux"))
84 return XcodeSDK::Linux
;
85 static_assert(XcodeSDK::Linux
== XcodeSDK::numSDKTypes
- 1,
86 "New SDK type was added, update this list!");
87 return XcodeSDK::unknown
;
90 static llvm::VersionTuple
ParseSDKVersion(llvm::StringRef
&name
) {
92 while (i
< name
.size() && name
[i
] >= '0' && name
[i
] <= '9')
94 if (i
== name
.size() || name
[i
++] != '.')
96 while (i
< name
.size() && name
[i
] >= '0' && name
[i
] <= '9')
98 if (i
== name
.size() || name
[i
++] != '.')
101 llvm::VersionTuple version
;
102 version
.tryParse(name
.slice(0, i
- 1));
103 name
= name
.drop_front(i
);
107 static bool ParseAppleInternalSDK(llvm::StringRef
&name
) {
108 return name
.consume_front("Internal.") || name
.consume_front(".Internal.");
111 XcodeSDK::Info
XcodeSDK::Parse() const {
113 llvm::StringRef
input(m_name
);
114 info
.type
= ParseSDKName(input
);
115 info
.version
= ParseSDKVersion(input
);
116 info
.internal
= ParseAppleInternalSDK(input
);
120 bool XcodeSDK::IsAppleInternalSDK() const {
121 llvm::StringRef
input(m_name
);
123 ParseSDKVersion(input
);
124 return ParseAppleInternalSDK(input
);
127 llvm::VersionTuple
XcodeSDK::GetVersion() const {
128 llvm::StringRef
input(m_name
);
130 return ParseSDKVersion(input
);
133 XcodeSDK::Type
XcodeSDK::GetType() const {
134 llvm::StringRef
input(m_name
);
135 return ParseSDKName(input
);
138 llvm::StringRef
XcodeSDK::GetString() const { return m_name
; }
140 bool XcodeSDK::Info::operator<(const Info
&other
) const {
141 return std::tie(type
, version
, internal
) <
142 std::tie(other
.type
, other
.version
, other
.internal
);
145 bool XcodeSDK::Info::operator==(const Info
&other
) const {
146 return std::tie(type
, version
, internal
) ==
147 std::tie(other
.type
, other
.version
, other
.internal
);
150 void XcodeSDK::Merge(const XcodeSDK
&other
) {
151 // The "bigger" SDK always wins.
153 auto r
= other
.Parse();
157 // The Internal flag always wins.
158 if (llvm::StringRef(m_name
).endswith(".sdk"))
159 if (!l
.internal
&& r
.internal
)
161 m_name
.substr(0, m_name
.size() - 3) + std::string("Internal.sdk");
165 std::string
XcodeSDK::GetCanonicalName(XcodeSDK::Info info
) {
171 case iPhoneSimulator
:
172 name
= "iphonesimulator";
177 case AppleTVSimulator
:
178 name
= "appletvsimulator";
184 name
= "watchsimulator";
198 if (!info
.version
.empty())
199 name
+= info
.version
.getAsString();
205 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type
,
206 llvm::VersionTuple version
) {
209 return version
>= llvm::VersionTuple(10, 10);
211 case Type::iPhoneSimulator
:
212 case Type::AppleTVOS
:
213 case Type::AppleTVSimulator
:
214 return version
>= llvm::VersionTuple(8);
216 case Type::WatchSimulator
:
217 return version
>= llvm::VersionTuple(6);
225 bool XcodeSDK::SupportsSwift() const {
226 XcodeSDK::Info info
= Parse();
229 return info
.version
.empty() || info
.version
>= llvm::VersionTuple(10, 10);
231 case Type::iPhoneSimulator
:
232 return info
.version
.empty() || info
.version
>= llvm::VersionTuple(8);
233 case Type::AppleTVSimulator
:
234 case Type::AppleTVOS
:
235 return info
.version
.empty() || info
.version
>= llvm::VersionTuple(9);
236 case Type::WatchSimulator
:
238 return info
.version
.empty() || info
.version
>= llvm::VersionTuple(2);
246 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type
,
247 const FileSpec
&sdk_path
) {
248 ConstString last_path_component
= sdk_path
.GetLastPathComponent();
250 if (!last_path_component
)
253 XcodeSDK
sdk(last_path_component
.GetStringRef().str());
254 if (sdk
.GetType() != desired_type
)
256 return SDKSupportsModules(sdk
.GetType(), sdk
.GetVersion());
259 XcodeSDK::Type
XcodeSDK::GetSDKTypeForTriple(const llvm::Triple
&triple
) {
260 using namespace llvm
;
261 switch (triple
.getOS()) {
264 return XcodeSDK::MacOSX
;
266 switch (triple
.getEnvironment()) {
268 return XcodeSDK::MacOSX
;
269 case Triple::Simulator
:
270 return XcodeSDK::iPhoneSimulator
;
272 return XcodeSDK::iPhoneOS
;
275 if (triple
.getEnvironment() == Triple::Simulator
)
276 return XcodeSDK::AppleTVSimulator
;
277 return XcodeSDK::AppleTVOS
;
278 case Triple::WatchOS
:
279 if (triple
.getEnvironment() == Triple::Simulator
)
280 return XcodeSDK::WatchSimulator
;
281 return XcodeSDK::watchOS
;
283 return XcodeSDK::Linux
;
285 return XcodeSDK::unknown
;
289 std::string
XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path
) {
290 auto begin
= llvm::sys::path::begin(path
);
291 auto end
= llvm::sys::path::end(path
);
293 // Iterate over the path components until we find something that ends with
294 // .app. If the next component is Contents then we've found the Contents
296 for (auto it
= begin
; it
!= end
; ++it
) {
297 if (it
->endswith(".app")) {
299 if (++next
!= end
&& *next
== "Contents") {
300 llvm::SmallString
<128> buffer
;
301 llvm::sys::path::append(buffer
, begin
, ++next
,
302 llvm::sys::path::Style::posix
);
303 return buffer
.str().str();