11e05d7b3SAdrian Prantl //===-- XcodeSDK.cpp ------------------------------------------------------===//
21e05d7b3SAdrian Prantl //
31e05d7b3SAdrian Prantl // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41e05d7b3SAdrian Prantl // See https://llvm.org/LICENSE.txt for license information.
51e05d7b3SAdrian Prantl // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61e05d7b3SAdrian Prantl //
71e05d7b3SAdrian Prantl //===----------------------------------------------------------------------===//
81e05d7b3SAdrian Prantl 
91e05d7b3SAdrian Prantl #include "lldb/Utility/FileSpec.h"
101e05d7b3SAdrian Prantl #include "lldb/Utility/XcodeSDK.h"
111e05d7b3SAdrian Prantl 
121e05d7b3SAdrian Prantl #include "lldb/lldb-types.h"
131e05d7b3SAdrian Prantl 
141e05d7b3SAdrian Prantl using namespace lldb;
151e05d7b3SAdrian Prantl using namespace lldb_private;
161e05d7b3SAdrian Prantl 
171e05d7b3SAdrian Prantl XcodeSDK &XcodeSDK::operator=(XcodeSDK other) {
181e05d7b3SAdrian Prantl   m_name = other.m_name;
191e05d7b3SAdrian Prantl   return *this;
201e05d7b3SAdrian Prantl }
211e05d7b3SAdrian Prantl 
221e05d7b3SAdrian Prantl bool XcodeSDK::operator==(XcodeSDK other) {
231e05d7b3SAdrian Prantl   return m_name == other.m_name;
241e05d7b3SAdrian Prantl }
251e05d7b3SAdrian Prantl 
261e05d7b3SAdrian Prantl static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
271e05d7b3SAdrian Prantl   if (name.consume_front("MacOSX"))
281e05d7b3SAdrian Prantl     return XcodeSDK::MacOSX;
291e05d7b3SAdrian Prantl   if (name.consume_front("iPhoneSimulator"))
301e05d7b3SAdrian Prantl     return XcodeSDK::iPhoneSimulator;
311e05d7b3SAdrian Prantl   if (name.consume_front("iPhoneOS"))
321e05d7b3SAdrian Prantl     return XcodeSDK::iPhoneOS;
331e05d7b3SAdrian Prantl   if (name.consume_front("AppleTVSimulator"))
341e05d7b3SAdrian Prantl     return XcodeSDK::AppleTVSimulator;
351e05d7b3SAdrian Prantl   if (name.consume_front("AppleTVOS"))
361e05d7b3SAdrian Prantl     return XcodeSDK::AppleTVOS;
371e05d7b3SAdrian Prantl   if (name.consume_front("WatchSimulator"))
381e05d7b3SAdrian Prantl     return XcodeSDK::WatchSimulator;
391e05d7b3SAdrian Prantl   if (name.consume_front("WatchOS"))
401e05d7b3SAdrian Prantl     return XcodeSDK::watchOS;
411e05d7b3SAdrian Prantl   if (name.consume_front("bridgeOS"))
421e05d7b3SAdrian Prantl     return XcodeSDK::bridgeOS;
431e05d7b3SAdrian Prantl   if (name.consume_front("Linux"))
441e05d7b3SAdrian Prantl     return XcodeSDK::Linux;
451e05d7b3SAdrian Prantl   static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
461e05d7b3SAdrian Prantl                 "New SDK type was added, update this list!");
471e05d7b3SAdrian Prantl   return XcodeSDK::unknown;
481e05d7b3SAdrian Prantl }
491e05d7b3SAdrian Prantl 
501e05d7b3SAdrian Prantl static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
511e05d7b3SAdrian Prantl   unsigned i = 0;
521e05d7b3SAdrian Prantl   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
531e05d7b3SAdrian Prantl     ++i;
541e05d7b3SAdrian Prantl   if (i == name.size() || name[i++] != '.')
551e05d7b3SAdrian Prantl     return {};
561e05d7b3SAdrian Prantl   while (i < name.size() && name[i] >= '0' && name[i] <= '9')
571e05d7b3SAdrian Prantl     ++i;
581e05d7b3SAdrian Prantl   if (i == name.size() || name[i++] != '.')
591e05d7b3SAdrian Prantl     return {};
601e05d7b3SAdrian Prantl 
611e05d7b3SAdrian Prantl   llvm::VersionTuple version;
621e05d7b3SAdrian Prantl   version.tryParse(name.slice(0, i - 1));
631e05d7b3SAdrian Prantl   name = name.drop_front(i);
641e05d7b3SAdrian Prantl   return version;
651e05d7b3SAdrian Prantl }
661e05d7b3SAdrian Prantl 
67*79feafa5SAdrian Prantl static bool ParseAppleInternalSDK(llvm::StringRef &name) {
68*79feafa5SAdrian Prantl   return name.consume_front("Internal.");
69*79feafa5SAdrian Prantl }
701e05d7b3SAdrian Prantl 
71*79feafa5SAdrian Prantl XcodeSDK::Info XcodeSDK::Parse() const {
72*79feafa5SAdrian Prantl   XcodeSDK::Info info;
731e05d7b3SAdrian Prantl   llvm::StringRef input(m_name);
74*79feafa5SAdrian Prantl   info.type = ParseSDKName(input);
75*79feafa5SAdrian Prantl   info.version = ParseSDKVersion(input);
76*79feafa5SAdrian Prantl   info.internal = ParseAppleInternalSDK(input);
77*79feafa5SAdrian Prantl   return info;
78*79feafa5SAdrian Prantl }
79*79feafa5SAdrian Prantl 
80*79feafa5SAdrian Prantl bool XcodeSDK::IsAppleInternalSDK() const {
81*79feafa5SAdrian Prantl   llvm::StringRef input(m_name);
82*79feafa5SAdrian Prantl   ParseSDKName(input);
83*79feafa5SAdrian Prantl   ParseSDKVersion(input);
84*79feafa5SAdrian Prantl   return ParseAppleInternalSDK(input);
851e05d7b3SAdrian Prantl }
861e05d7b3SAdrian Prantl 
871e05d7b3SAdrian Prantl llvm::VersionTuple XcodeSDK::GetVersion() const {
881e05d7b3SAdrian Prantl   llvm::StringRef input(m_name);
891e05d7b3SAdrian Prantl   ParseSDKName(input);
901e05d7b3SAdrian Prantl   return ParseSDKVersion(input);
911e05d7b3SAdrian Prantl }
921e05d7b3SAdrian Prantl 
931e05d7b3SAdrian Prantl XcodeSDK::Type XcodeSDK::GetType() const {
941e05d7b3SAdrian Prantl   llvm::StringRef input(m_name);
951e05d7b3SAdrian Prantl   return ParseSDKName(input);
961e05d7b3SAdrian Prantl }
971e05d7b3SAdrian Prantl 
981e05d7b3SAdrian Prantl llvm::StringRef XcodeSDK::GetString() const { return m_name; }
991e05d7b3SAdrian Prantl 
100*79feafa5SAdrian Prantl bool XcodeSDK::Info::operator<(const Info &other) const {
101*79feafa5SAdrian Prantl   return std::tie(type, version, internal) <
102*79feafa5SAdrian Prantl          std::tie(other.type, other.version, other.internal);
103*79feafa5SAdrian Prantl }
1041e05d7b3SAdrian Prantl void XcodeSDK::Merge(XcodeSDK other) {
1051e05d7b3SAdrian Prantl   // The "bigger" SDK always wins.
106*79feafa5SAdrian Prantl   auto l = Parse();
107*79feafa5SAdrian Prantl   auto r = other.Parse();
108*79feafa5SAdrian Prantl   if (l < r)
1091e05d7b3SAdrian Prantl     *this = other;
110*79feafa5SAdrian Prantl   else {
111*79feafa5SAdrian Prantl     // The Internal flag always wins.
112*79feafa5SAdrian Prantl     if (llvm::StringRef(m_name).endswith(".sdk"))
113*79feafa5SAdrian Prantl       if (!l.internal && r.internal)
114*79feafa5SAdrian Prantl         m_name =
115*79feafa5SAdrian Prantl             m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
116*79feafa5SAdrian Prantl   }
1171e05d7b3SAdrian Prantl }
1181e05d7b3SAdrian Prantl 
119*79feafa5SAdrian Prantl std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
120*79feafa5SAdrian Prantl   std::string name;
121*79feafa5SAdrian Prantl   switch (info.type) {
1221e05d7b3SAdrian Prantl   case MacOSX:
123*79feafa5SAdrian Prantl     name = "macosx";
124*79feafa5SAdrian Prantl     break;
1251e05d7b3SAdrian Prantl   case iPhoneSimulator:
126*79feafa5SAdrian Prantl     name = "iphonesimulator";
127*79feafa5SAdrian Prantl     break;
1281e05d7b3SAdrian Prantl   case iPhoneOS:
129*79feafa5SAdrian Prantl     name = "iphoneos";
130*79feafa5SAdrian Prantl     break;
1311e05d7b3SAdrian Prantl   case AppleTVSimulator:
132*79feafa5SAdrian Prantl     name = "appletvsimulator";
133*79feafa5SAdrian Prantl     break;
1341e05d7b3SAdrian Prantl   case AppleTVOS:
135*79feafa5SAdrian Prantl     name = "appletvos";
136*79feafa5SAdrian Prantl     break;
1371e05d7b3SAdrian Prantl   case WatchSimulator:
138*79feafa5SAdrian Prantl     name = "watchsimulator";
139*79feafa5SAdrian Prantl     break;
1401e05d7b3SAdrian Prantl   case watchOS:
141*79feafa5SAdrian Prantl     name = "watchos";
142*79feafa5SAdrian Prantl     break;
1431e05d7b3SAdrian Prantl   case bridgeOS:
144*79feafa5SAdrian Prantl     name = "bridgeos";
145*79feafa5SAdrian Prantl     break;
1461e05d7b3SAdrian Prantl   case Linux:
147*79feafa5SAdrian Prantl     name = "linux";
148*79feafa5SAdrian Prantl     break;
1491e05d7b3SAdrian Prantl   case numSDKTypes:
1501e05d7b3SAdrian Prantl   case unknown:
151*79feafa5SAdrian Prantl     return {};
1521e05d7b3SAdrian Prantl   }
153*79feafa5SAdrian Prantl   if (!info.version.empty())
154*79feafa5SAdrian Prantl     name += info.version.getAsString();
155*79feafa5SAdrian Prantl   if (info.internal)
156*79feafa5SAdrian Prantl     name += ".internal";
157*79feafa5SAdrian Prantl   return name;
1581e05d7b3SAdrian Prantl }
1591e05d7b3SAdrian Prantl 
1601e05d7b3SAdrian Prantl bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
1611e05d7b3SAdrian Prantl                                   llvm::VersionTuple version) {
1621e05d7b3SAdrian Prantl   switch (sdk_type) {
1631e05d7b3SAdrian Prantl   case Type::MacOSX:
1641e05d7b3SAdrian Prantl     return version >= llvm::VersionTuple(10, 10);
1651e05d7b3SAdrian Prantl   case Type::iPhoneOS:
1661e05d7b3SAdrian Prantl   case Type::iPhoneSimulator:
1671e05d7b3SAdrian Prantl   case Type::AppleTVOS:
1681e05d7b3SAdrian Prantl   case Type::AppleTVSimulator:
1691e05d7b3SAdrian Prantl     return version >= llvm::VersionTuple(8);
1701e05d7b3SAdrian Prantl   case Type::watchOS:
1711e05d7b3SAdrian Prantl   case Type::WatchSimulator:
1721e05d7b3SAdrian Prantl     return version >= llvm::VersionTuple(6);
1731e05d7b3SAdrian Prantl   default:
1741e05d7b3SAdrian Prantl     return false;
1751e05d7b3SAdrian Prantl   }
1761e05d7b3SAdrian Prantl 
1771e05d7b3SAdrian Prantl   return false;
1781e05d7b3SAdrian Prantl }
1791e05d7b3SAdrian Prantl 
1801e05d7b3SAdrian Prantl bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
1811e05d7b3SAdrian Prantl                                   const FileSpec &sdk_path) {
1821e05d7b3SAdrian Prantl   ConstString last_path_component = sdk_path.GetLastPathComponent();
1831e05d7b3SAdrian Prantl 
1841e05d7b3SAdrian Prantl   if (last_path_component) {
1851e05d7b3SAdrian Prantl     const llvm::StringRef sdk_name = last_path_component.GetStringRef();
1861e05d7b3SAdrian Prantl 
1871e05d7b3SAdrian Prantl     const std::string sdk_name_lower = sdk_name.lower();
188*79feafa5SAdrian Prantl     Info info;
189*79feafa5SAdrian Prantl     info.type = desired_type;
190*79feafa5SAdrian Prantl     const llvm::StringRef sdk_string = GetCanonicalName(info);
1911e05d7b3SAdrian Prantl     if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string))
1921e05d7b3SAdrian Prantl       return false;
1931e05d7b3SAdrian Prantl 
1941e05d7b3SAdrian Prantl     auto version_part = sdk_name.drop_front(sdk_string.size());
1951e05d7b3SAdrian Prantl     version_part.consume_back(".sdk");
196*79feafa5SAdrian Prantl     version_part.consume_back(".Internal");
1971e05d7b3SAdrian Prantl 
1981e05d7b3SAdrian Prantl     llvm::VersionTuple version;
1991e05d7b3SAdrian Prantl     if (version.tryParse(version_part))
2001e05d7b3SAdrian Prantl       return false;
2011e05d7b3SAdrian Prantl     return SDKSupportsModules(desired_type, version);
2021e05d7b3SAdrian Prantl   }
2031e05d7b3SAdrian Prantl 
2041e05d7b3SAdrian Prantl   return false;
2051e05d7b3SAdrian Prantl }
206