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/FileSpec.h"
10 #include "lldb/Utility/XcodeSDK.h"
11 
12 #include "lldb/lldb-types.h"
13 
14 using namespace lldb;
15 using namespace lldb_private;
16 
17 XcodeSDK &XcodeSDK::operator=(XcodeSDK other) {
18   m_name = other.m_name;
19   return *this;
20 }
21 
22 bool XcodeSDK::operator==(XcodeSDK other) {
23   return m_name == other.m_name;
24 }
25 
26 static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
27   if (name.consume_front("MacOSX"))
28     return XcodeSDK::MacOSX;
29   if (name.consume_front("iPhoneSimulator"))
30     return XcodeSDK::iPhoneSimulator;
31   if (name.consume_front("iPhoneOS"))
32     return XcodeSDK::iPhoneOS;
33   if (name.consume_front("AppleTVSimulator"))
34     return XcodeSDK::AppleTVSimulator;
35   if (name.consume_front("AppleTVOS"))
36     return XcodeSDK::AppleTVOS;
37   if (name.consume_front("WatchSimulator"))
38     return XcodeSDK::WatchSimulator;
39   if (name.consume_front("WatchOS"))
40     return XcodeSDK::watchOS;
41   if (name.consume_front("bridgeOS"))
42     return XcodeSDK::bridgeOS;
43   if (name.consume_front("Linux"))
44     return XcodeSDK::Linux;
45   static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
46                 "New SDK type was added, update this list!");
47   return XcodeSDK::unknown;
48 }
49 
50 static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
51   unsigned i = 0;
52   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
53     ++i;
54   if (i == name.size() || name[i++] != '.')
55     return {};
56   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
57     ++i;
58   if (i == name.size() || name[i++] != '.')
59     return {};
60 
61   llvm::VersionTuple version;
62   version.tryParse(name.slice(0, i - 1));
63   name = name.drop_front(i);
64   return version;
65 }
66 
67 
68 std::tuple<XcodeSDK::Type, llvm::VersionTuple> XcodeSDK::Parse() const {
69   llvm::StringRef input(m_name);
70   XcodeSDK::Type sdk = ParseSDKName(input);
71   llvm::VersionTuple version = ParseSDKVersion(input);
72   return std::make_tuple<XcodeSDK::Type, llvm::VersionTuple>(
73       std::move(sdk), std::move(version));
74 }
75 
76 llvm::VersionTuple XcodeSDK::GetVersion() const {
77   llvm::StringRef input(m_name);
78   ParseSDKName(input);
79   return ParseSDKVersion(input);
80 }
81 
82 XcodeSDK::Type XcodeSDK::GetType() const {
83   llvm::StringRef input(m_name);
84   return ParseSDKName(input);
85 }
86 
87 llvm::StringRef XcodeSDK::GetString() const { return m_name; }
88 
89 void XcodeSDK::Merge(XcodeSDK other) {
90   // The "bigger" SDK always wins.
91   if (Parse() < other.Parse())
92     *this = other;
93 }
94 
95 llvm::StringRef XcodeSDK::GetSDKNameForType(XcodeSDK::Type type) {
96   switch (type) {
97   case MacOSX:
98     return "macosx";
99   case iPhoneSimulator:
100     return "iphonesimulator";
101   case iPhoneOS:
102     return "iphoneos";
103   case AppleTVSimulator:
104     return "appletvsimulator";
105   case AppleTVOS:
106     return "appletvos";
107   case WatchSimulator:
108     return "watchsimulator";
109   case watchOS:
110     return "watchos";
111   case bridgeOS:
112     return "bridgeos";
113   case Linux:
114     return "linux";
115   case numSDKTypes:
116   case unknown:
117     return "";
118   }
119   llvm_unreachable("unhandled switch case");
120 }
121 
122 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
123                                   llvm::VersionTuple version) {
124   switch (sdk_type) {
125   case Type::MacOSX:
126     return version >= llvm::VersionTuple(10, 10);
127   case Type::iPhoneOS:
128   case Type::iPhoneSimulator:
129   case Type::AppleTVOS:
130   case Type::AppleTVSimulator:
131     return version >= llvm::VersionTuple(8);
132   case Type::watchOS:
133   case Type::WatchSimulator:
134     return version >= llvm::VersionTuple(6);
135   default:
136     return false;
137   }
138 
139   return false;
140 }
141 
142 bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
143                                   const FileSpec &sdk_path) {
144   ConstString last_path_component = sdk_path.GetLastPathComponent();
145 
146   if (last_path_component) {
147     const llvm::StringRef sdk_name = last_path_component.GetStringRef();
148 
149     const std::string sdk_name_lower = sdk_name.lower();
150     const llvm::StringRef sdk_string = GetSDKNameForType(desired_type);
151     if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string))
152       return false;
153 
154     auto version_part = sdk_name.drop_front(sdk_string.size());
155     version_part.consume_back(".sdk");
156 
157     llvm::VersionTuple version;
158     if (version.tryParse(version_part))
159       return false;
160     return SDKSupportsModules(desired_type, version);
161   }
162 
163   return false;
164 }
165