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/ADT/Triple.h"
15 
16 #include <string>
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
21 XcodeSDK &XcodeSDK::operator=(XcodeSDK other) {
22   m_name = other.m_name;
23   return *this;
24 }
25 
26 bool XcodeSDK::operator==(XcodeSDK other) {
27   return m_name == other.m_name;
28 }
29 
30 static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
31   if (name.consume_front("MacOSX"))
32     return XcodeSDK::MacOSX;
33   if (name.consume_front("iPhoneSimulator"))
34     return XcodeSDK::iPhoneSimulator;
35   if (name.consume_front("iPhoneOS"))
36     return XcodeSDK::iPhoneOS;
37   if (name.consume_front("AppleTVSimulator"))
38     return XcodeSDK::AppleTVSimulator;
39   if (name.consume_front("AppleTVOS"))
40     return XcodeSDK::AppleTVOS;
41   if (name.consume_front("WatchSimulator"))
42     return XcodeSDK::WatchSimulator;
43   if (name.consume_front("WatchOS"))
44     return XcodeSDK::watchOS;
45   if (name.consume_front("bridgeOS"))
46     return XcodeSDK::bridgeOS;
47   if (name.consume_front("Linux"))
48     return XcodeSDK::Linux;
49   static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
50                 "New SDK type was added, update this list!");
51   return XcodeSDK::unknown;
52 }
53 
54 static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
55   unsigned i = 0;
56   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
57     ++i;
58   if (i == name.size() || name[i++] != '.')
59     return {};
60   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
61     ++i;
62   if (i == name.size() || name[i++] != '.')
63     return {};
64 
65   llvm::VersionTuple version;
66   version.tryParse(name.slice(0, i - 1));
67   name = name.drop_front(i);
68   return version;
69 }
70 
71 static bool ParseAppleInternalSDK(llvm::StringRef &name) {
72   return name.consume_front("Internal.");
73 }
74 
75 XcodeSDK::Info XcodeSDK::Parse() const {
76   XcodeSDK::Info info;
77   llvm::StringRef input(m_name);
78   info.type = ParseSDKName(input);
79   info.version = ParseSDKVersion(input);
80   info.internal = ParseAppleInternalSDK(input);
81   return info;
82 }
83 
84 bool XcodeSDK::IsAppleInternalSDK() const {
85   llvm::StringRef input(m_name);
86   ParseSDKName(input);
87   ParseSDKVersion(input);
88   return ParseAppleInternalSDK(input);
89 }
90 
91 llvm::VersionTuple XcodeSDK::GetVersion() const {
92   llvm::StringRef input(m_name);
93   ParseSDKName(input);
94   return ParseSDKVersion(input);
95 }
96 
97 XcodeSDK::Type XcodeSDK::GetType() const {
98   llvm::StringRef input(m_name);
99   return ParseSDKName(input);
100 }
101 
102 llvm::StringRef XcodeSDK::GetString() const { return m_name; }
103 
104 bool XcodeSDK::Info::operator<(const Info &other) const {
105   return std::tie(type, version, internal) <
106          std::tie(other.type, other.version, other.internal);
107 }
108 void XcodeSDK::Merge(XcodeSDK other) {
109   // The "bigger" SDK always wins.
110   auto l = Parse();
111   auto r = other.Parse();
112   if (l < r)
113     *this = other;
114   else {
115     // The Internal flag always wins.
116     if (llvm::StringRef(m_name).endswith(".sdk"))
117       if (!l.internal && r.internal)
118         m_name =
119             m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
120   }
121 }
122 
123 std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
124   std::string name;
125   switch (info.type) {
126   case MacOSX:
127     name = "macosx";
128     break;
129   case iPhoneSimulator:
130     name = "iphonesimulator";
131     break;
132   case iPhoneOS:
133     name = "iphoneos";
134     break;
135   case AppleTVSimulator:
136     name = "appletvsimulator";
137     break;
138   case AppleTVOS:
139     name = "appletvos";
140     break;
141   case WatchSimulator:
142     name = "watchsimulator";
143     break;
144   case watchOS:
145     name = "watchos";
146     break;
147   case bridgeOS:
148     name = "bridgeos";
149     break;
150   case Linux:
151     name = "linux";
152     break;
153   case numSDKTypes:
154   case unknown:
155     return {};
156   }
157   if (!info.version.empty())
158     name += info.version.getAsString();
159   if (info.internal)
160     name += ".internal";
161   return name;
162 }
163 
164 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
165                                   llvm::VersionTuple version) {
166   switch (sdk_type) {
167   case Type::MacOSX:
168     return version >= llvm::VersionTuple(10, 10);
169   case Type::iPhoneOS:
170   case Type::iPhoneSimulator:
171   case Type::AppleTVOS:
172   case Type::AppleTVSimulator:
173     return version >= llvm::VersionTuple(8);
174   case Type::watchOS:
175   case Type::WatchSimulator:
176     return version >= llvm::VersionTuple(6);
177   default:
178     return false;
179   }
180 
181   return false;
182 }
183 
184 bool XcodeSDK::SupportsSwift() const {
185   XcodeSDK::Info info = Parse();
186   switch (info.type) {
187   case Type::MacOSX:
188     return info.version.empty() || info.version >= llvm::VersionTuple(10, 10);
189   case Type::iPhoneOS:
190   case Type::iPhoneSimulator:
191     return info.version.empty() || info.version >= llvm::VersionTuple(8);
192   case Type::AppleTVSimulator:
193   case Type::AppleTVOS:
194     return info.version.empty() || info.version >= llvm::VersionTuple(9);
195   case Type::WatchSimulator:
196   case Type::watchOS:
197     return info.version.empty() || info.version >= llvm::VersionTuple(2);
198   case Type::Linux:
199     return true;
200   default:
201     return false;
202   }
203 }
204 
205 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
206                                   const FileSpec &sdk_path) {
207   ConstString last_path_component = sdk_path.GetLastPathComponent();
208 
209   if (!last_path_component)
210     return false;
211 
212   XcodeSDK sdk(last_path_component.GetStringRef().str());
213   if (sdk.GetType() != desired_type)
214     return false;
215   return SDKSupportsModules(sdk.GetType(), sdk.GetVersion());
216 }
217 
218 XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) {
219   using namespace llvm;
220   switch (triple.getOS()) {
221   case Triple::MacOSX:
222   case Triple::Darwin:
223     return XcodeSDK::MacOSX;
224   case Triple::IOS:
225     switch (triple.getEnvironment()) {
226     case Triple::MacABI:
227       return XcodeSDK::MacOSX;
228     case Triple::Simulator:
229       return XcodeSDK::iPhoneSimulator;
230     default:
231       return XcodeSDK::iPhoneOS;
232     }
233   case Triple::TvOS:
234     if (triple.getEnvironment() == Triple::Simulator)
235       return XcodeSDK::AppleTVSimulator;
236     return XcodeSDK::AppleTVOS;
237   case Triple::WatchOS:
238     if (triple.getEnvironment() == Triple::Simulator)
239       return XcodeSDK::WatchSimulator;
240     return XcodeSDK::watchOS;
241   case Triple::Linux:
242     return XcodeSDK::Linux;
243   default:
244     return XcodeSDK::unknown;
245   }
246 }
247