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/XcodeSDK.h"
106e95d51eSAdrian Prantl #include "lldb/Utility/FileSpec.h"
111e05d7b3SAdrian Prantl
121e05d7b3SAdrian Prantl #include "lldb/lldb-types.h"
136e95d51eSAdrian Prantl
146e95d51eSAdrian Prantl #include "llvm/ADT/Triple.h"
156e95d51eSAdrian Prantl
166a9edce2SEric Christopher #include <string>
171e05d7b3SAdrian Prantl
181e05d7b3SAdrian Prantl using namespace lldb;
191e05d7b3SAdrian Prantl using namespace lldb_private;
201e05d7b3SAdrian Prantl
GetName(XcodeSDK::Type type)21ae920a81SAdrian Prantl static llvm::StringRef GetName(XcodeSDK::Type type) {
22ae920a81SAdrian Prantl switch (type) {
23ae920a81SAdrian Prantl case XcodeSDK::MacOSX:
24ae920a81SAdrian Prantl return "MacOSX";
25ae920a81SAdrian Prantl case XcodeSDK::iPhoneSimulator:
26ae920a81SAdrian Prantl return "iPhoneSimulator";
27ae920a81SAdrian Prantl case XcodeSDK::iPhoneOS:
28ae920a81SAdrian Prantl return "iPhoneOS";
29ae920a81SAdrian Prantl case XcodeSDK::AppleTVSimulator:
30ae920a81SAdrian Prantl return "AppleTVSimulator";
31ae920a81SAdrian Prantl case XcodeSDK::AppleTVOS:
32ae920a81SAdrian Prantl return "AppleTVOS";
33ae920a81SAdrian Prantl case XcodeSDK::WatchSimulator:
34ae920a81SAdrian Prantl return "WatchSimulator";
35ae920a81SAdrian Prantl case XcodeSDK::watchOS:
36ae920a81SAdrian Prantl return "WatchOS";
37ae920a81SAdrian Prantl case XcodeSDK::bridgeOS:
38ae920a81SAdrian Prantl return "bridgeOS";
39ae920a81SAdrian Prantl case XcodeSDK::Linux:
40ae920a81SAdrian Prantl return "Linux";
41ae920a81SAdrian Prantl case XcodeSDK::unknown:
42ae920a81SAdrian Prantl return {};
43ae920a81SAdrian Prantl }
44dac6e9caSPavel Labath llvm_unreachable("Unhandled sdk type!");
45ae920a81SAdrian Prantl }
46ae920a81SAdrian Prantl
XcodeSDK(XcodeSDK::Info info)47ae920a81SAdrian Prantl XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) {
48ae920a81SAdrian Prantl if (!m_name.empty()) {
49ae920a81SAdrian Prantl if (!info.version.empty())
50ae920a81SAdrian Prantl m_name += info.version.getAsString();
51ae920a81SAdrian Prantl if (info.internal)
52ae920a81SAdrian Prantl m_name += ".Internal";
53ae920a81SAdrian Prantl m_name += ".sdk";
54ae920a81SAdrian Prantl }
55ae920a81SAdrian Prantl }
56ae920a81SAdrian Prantl
57*24f9a2f5SShafik Yaghmour XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) = default;
581e05d7b3SAdrian Prantl
operator ==(const XcodeSDK & other)590d5fc822SJonas Devlieghere bool XcodeSDK::operator==(const XcodeSDK &other) {
601e05d7b3SAdrian Prantl return m_name == other.m_name;
611e05d7b3SAdrian Prantl }
621e05d7b3SAdrian Prantl
ParseSDKName(llvm::StringRef & name)631e05d7b3SAdrian Prantl static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
641e05d7b3SAdrian Prantl if (name.consume_front("MacOSX"))
651e05d7b3SAdrian Prantl return XcodeSDK::MacOSX;
661e05d7b3SAdrian Prantl if (name.consume_front("iPhoneSimulator"))
671e05d7b3SAdrian Prantl return XcodeSDK::iPhoneSimulator;
681e05d7b3SAdrian Prantl if (name.consume_front("iPhoneOS"))
691e05d7b3SAdrian Prantl return XcodeSDK::iPhoneOS;
701e05d7b3SAdrian Prantl if (name.consume_front("AppleTVSimulator"))
711e05d7b3SAdrian Prantl return XcodeSDK::AppleTVSimulator;
721e05d7b3SAdrian Prantl if (name.consume_front("AppleTVOS"))
731e05d7b3SAdrian Prantl return XcodeSDK::AppleTVOS;
741e05d7b3SAdrian Prantl if (name.consume_front("WatchSimulator"))
751e05d7b3SAdrian Prantl return XcodeSDK::WatchSimulator;
761e05d7b3SAdrian Prantl if (name.consume_front("WatchOS"))
771e05d7b3SAdrian Prantl return XcodeSDK::watchOS;
781e05d7b3SAdrian Prantl if (name.consume_front("bridgeOS"))
791e05d7b3SAdrian Prantl return XcodeSDK::bridgeOS;
801e05d7b3SAdrian Prantl if (name.consume_front("Linux"))
811e05d7b3SAdrian Prantl return XcodeSDK::Linux;
821e05d7b3SAdrian Prantl static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
831e05d7b3SAdrian Prantl "New SDK type was added, update this list!");
841e05d7b3SAdrian Prantl return XcodeSDK::unknown;
851e05d7b3SAdrian Prantl }
861e05d7b3SAdrian Prantl
ParseSDKVersion(llvm::StringRef & name)871e05d7b3SAdrian Prantl static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
881e05d7b3SAdrian Prantl unsigned i = 0;
891e05d7b3SAdrian Prantl while (i < name.size() && name[i] >= '0' && name[i] <= '9')
901e05d7b3SAdrian Prantl ++i;
911e05d7b3SAdrian Prantl if (i == name.size() || name[i++] != '.')
921e05d7b3SAdrian Prantl return {};
931e05d7b3SAdrian Prantl while (i < name.size() && name[i] >= '0' && name[i] <= '9')
941e05d7b3SAdrian Prantl ++i;
951e05d7b3SAdrian Prantl if (i == name.size() || name[i++] != '.')
961e05d7b3SAdrian Prantl return {};
971e05d7b3SAdrian Prantl
981e05d7b3SAdrian Prantl llvm::VersionTuple version;
991e05d7b3SAdrian Prantl version.tryParse(name.slice(0, i - 1));
1001e05d7b3SAdrian Prantl name = name.drop_front(i);
1011e05d7b3SAdrian Prantl return version;
1021e05d7b3SAdrian Prantl }
1031e05d7b3SAdrian Prantl
ParseAppleInternalSDK(llvm::StringRef & name)10479feafa5SAdrian Prantl static bool ParseAppleInternalSDK(llvm::StringRef &name) {
105ae920a81SAdrian Prantl return name.consume_front("Internal.") || name.consume_front(".Internal.");
10679feafa5SAdrian Prantl }
1071e05d7b3SAdrian Prantl
Parse() const10879feafa5SAdrian Prantl XcodeSDK::Info XcodeSDK::Parse() const {
10979feafa5SAdrian Prantl XcodeSDK::Info info;
1101e05d7b3SAdrian Prantl llvm::StringRef input(m_name);
11179feafa5SAdrian Prantl info.type = ParseSDKName(input);
11279feafa5SAdrian Prantl info.version = ParseSDKVersion(input);
11379feafa5SAdrian Prantl info.internal = ParseAppleInternalSDK(input);
11479feafa5SAdrian Prantl return info;
11579feafa5SAdrian Prantl }
11679feafa5SAdrian Prantl
IsAppleInternalSDK() const11779feafa5SAdrian Prantl bool XcodeSDK::IsAppleInternalSDK() const {
11879feafa5SAdrian Prantl llvm::StringRef input(m_name);
11979feafa5SAdrian Prantl ParseSDKName(input);
12079feafa5SAdrian Prantl ParseSDKVersion(input);
12179feafa5SAdrian Prantl return ParseAppleInternalSDK(input);
1221e05d7b3SAdrian Prantl }
1231e05d7b3SAdrian Prantl
GetVersion() const1241e05d7b3SAdrian Prantl llvm::VersionTuple XcodeSDK::GetVersion() const {
1251e05d7b3SAdrian Prantl llvm::StringRef input(m_name);
1261e05d7b3SAdrian Prantl ParseSDKName(input);
1271e05d7b3SAdrian Prantl return ParseSDKVersion(input);
1281e05d7b3SAdrian Prantl }
1291e05d7b3SAdrian Prantl
GetType() const1301e05d7b3SAdrian Prantl XcodeSDK::Type XcodeSDK::GetType() const {
1311e05d7b3SAdrian Prantl llvm::StringRef input(m_name);
1321e05d7b3SAdrian Prantl return ParseSDKName(input);
1331e05d7b3SAdrian Prantl }
1341e05d7b3SAdrian Prantl
GetString() const1351e05d7b3SAdrian Prantl llvm::StringRef XcodeSDK::GetString() const { return m_name; }
1361e05d7b3SAdrian Prantl
operator <(const Info & other) const13779feafa5SAdrian Prantl bool XcodeSDK::Info::operator<(const Info &other) const {
13879feafa5SAdrian Prantl return std::tie(type, version, internal) <
13979feafa5SAdrian Prantl std::tie(other.type, other.version, other.internal);
14079feafa5SAdrian Prantl }
141ae920a81SAdrian Prantl
operator ==(const Info & other) const142ae920a81SAdrian Prantl bool XcodeSDK::Info::operator==(const Info &other) const {
143ae920a81SAdrian Prantl return std::tie(type, version, internal) ==
144ae920a81SAdrian Prantl std::tie(other.type, other.version, other.internal);
145ae920a81SAdrian Prantl }
146ae920a81SAdrian Prantl
Merge(const XcodeSDK & other)1470d5fc822SJonas Devlieghere void XcodeSDK::Merge(const XcodeSDK &other) {
1481e05d7b3SAdrian Prantl // The "bigger" SDK always wins.
14979feafa5SAdrian Prantl auto l = Parse();
15079feafa5SAdrian Prantl auto r = other.Parse();
15179feafa5SAdrian Prantl if (l < r)
1521e05d7b3SAdrian Prantl *this = other;
15379feafa5SAdrian Prantl else {
15479feafa5SAdrian Prantl // The Internal flag always wins.
15579feafa5SAdrian Prantl if (llvm::StringRef(m_name).endswith(".sdk"))
15679feafa5SAdrian Prantl if (!l.internal && r.internal)
15779feafa5SAdrian Prantl m_name =
15879feafa5SAdrian Prantl m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
15979feafa5SAdrian Prantl }
1601e05d7b3SAdrian Prantl }
1611e05d7b3SAdrian Prantl
GetCanonicalName(XcodeSDK::Info info)16279feafa5SAdrian Prantl std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
16379feafa5SAdrian Prantl std::string name;
16479feafa5SAdrian Prantl switch (info.type) {
1651e05d7b3SAdrian Prantl case MacOSX:
16679feafa5SAdrian Prantl name = "macosx";
16779feafa5SAdrian Prantl break;
1681e05d7b3SAdrian Prantl case iPhoneSimulator:
16979feafa5SAdrian Prantl name = "iphonesimulator";
17079feafa5SAdrian Prantl break;
1711e05d7b3SAdrian Prantl case iPhoneOS:
17279feafa5SAdrian Prantl name = "iphoneos";
17379feafa5SAdrian Prantl break;
1741e05d7b3SAdrian Prantl case AppleTVSimulator:
17579feafa5SAdrian Prantl name = "appletvsimulator";
17679feafa5SAdrian Prantl break;
1771e05d7b3SAdrian Prantl case AppleTVOS:
17879feafa5SAdrian Prantl name = "appletvos";
17979feafa5SAdrian Prantl break;
1801e05d7b3SAdrian Prantl case WatchSimulator:
18179feafa5SAdrian Prantl name = "watchsimulator";
18279feafa5SAdrian Prantl break;
1831e05d7b3SAdrian Prantl case watchOS:
18479feafa5SAdrian Prantl name = "watchos";
18579feafa5SAdrian Prantl break;
1861e05d7b3SAdrian Prantl case bridgeOS:
18779feafa5SAdrian Prantl name = "bridgeos";
18879feafa5SAdrian Prantl break;
1891e05d7b3SAdrian Prantl case Linux:
19079feafa5SAdrian Prantl name = "linux";
19179feafa5SAdrian Prantl break;
1921e05d7b3SAdrian Prantl case unknown:
19379feafa5SAdrian Prantl return {};
1941e05d7b3SAdrian Prantl }
19579feafa5SAdrian Prantl if (!info.version.empty())
19679feafa5SAdrian Prantl name += info.version.getAsString();
19779feafa5SAdrian Prantl if (info.internal)
19879feafa5SAdrian Prantl name += ".internal";
19979feafa5SAdrian Prantl return name;
2001e05d7b3SAdrian Prantl }
2011e05d7b3SAdrian Prantl
SDKSupportsModules(XcodeSDK::Type sdk_type,llvm::VersionTuple version)2021e05d7b3SAdrian Prantl bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
2031e05d7b3SAdrian Prantl llvm::VersionTuple version) {
2041e05d7b3SAdrian Prantl switch (sdk_type) {
2051e05d7b3SAdrian Prantl case Type::MacOSX:
2061e05d7b3SAdrian Prantl return version >= llvm::VersionTuple(10, 10);
2071e05d7b3SAdrian Prantl case Type::iPhoneOS:
2081e05d7b3SAdrian Prantl case Type::iPhoneSimulator:
2091e05d7b3SAdrian Prantl case Type::AppleTVOS:
2101e05d7b3SAdrian Prantl case Type::AppleTVSimulator:
2111e05d7b3SAdrian Prantl return version >= llvm::VersionTuple(8);
2121e05d7b3SAdrian Prantl case Type::watchOS:
2131e05d7b3SAdrian Prantl case Type::WatchSimulator:
2141e05d7b3SAdrian Prantl return version >= llvm::VersionTuple(6);
2151e05d7b3SAdrian Prantl default:
2161e05d7b3SAdrian Prantl return false;
2171e05d7b3SAdrian Prantl }
2181e05d7b3SAdrian Prantl
2191e05d7b3SAdrian Prantl return false;
2201e05d7b3SAdrian Prantl }
2211e05d7b3SAdrian Prantl
SupportsSwift() const222dec1c94eSAdrian Prantl bool XcodeSDK::SupportsSwift() const {
223dec1c94eSAdrian Prantl XcodeSDK::Info info = Parse();
224dec1c94eSAdrian Prantl switch (info.type) {
225dec1c94eSAdrian Prantl case Type::MacOSX:
226dec1c94eSAdrian Prantl return info.version.empty() || info.version >= llvm::VersionTuple(10, 10);
227dec1c94eSAdrian Prantl case Type::iPhoneOS:
228dec1c94eSAdrian Prantl case Type::iPhoneSimulator:
229dec1c94eSAdrian Prantl return info.version.empty() || info.version >= llvm::VersionTuple(8);
230dec1c94eSAdrian Prantl case Type::AppleTVSimulator:
231dec1c94eSAdrian Prantl case Type::AppleTVOS:
232dec1c94eSAdrian Prantl return info.version.empty() || info.version >= llvm::VersionTuple(9);
233dec1c94eSAdrian Prantl case Type::WatchSimulator:
234dec1c94eSAdrian Prantl case Type::watchOS:
235dec1c94eSAdrian Prantl return info.version.empty() || info.version >= llvm::VersionTuple(2);
236dec1c94eSAdrian Prantl case Type::Linux:
237dec1c94eSAdrian Prantl return true;
238dec1c94eSAdrian Prantl default:
239dec1c94eSAdrian Prantl return false;
240dec1c94eSAdrian Prantl }
241dec1c94eSAdrian Prantl }
242dec1c94eSAdrian Prantl
SDKSupportsModules(XcodeSDK::Type desired_type,const FileSpec & sdk_path)2431e05d7b3SAdrian Prantl bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
2441e05d7b3SAdrian Prantl const FileSpec &sdk_path) {
2451e05d7b3SAdrian Prantl ConstString last_path_component = sdk_path.GetLastPathComponent();
2461e05d7b3SAdrian Prantl
2474356aa20SAdrian Prantl if (!last_path_component)
2481e05d7b3SAdrian Prantl return false;
2491e05d7b3SAdrian Prantl
2504356aa20SAdrian Prantl XcodeSDK sdk(last_path_component.GetStringRef().str());
2514356aa20SAdrian Prantl if (sdk.GetType() != desired_type)
2521e05d7b3SAdrian Prantl return false;
2534356aa20SAdrian Prantl return SDKSupportsModules(sdk.GetType(), sdk.GetVersion());
2541e05d7b3SAdrian Prantl }
2556e95d51eSAdrian Prantl
GetSDKTypeForTriple(const llvm::Triple & triple)2566e95d51eSAdrian Prantl XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) {
2576e95d51eSAdrian Prantl using namespace llvm;
2586e95d51eSAdrian Prantl switch (triple.getOS()) {
2596e95d51eSAdrian Prantl case Triple::MacOSX:
2606e95d51eSAdrian Prantl case Triple::Darwin:
2616e95d51eSAdrian Prantl return XcodeSDK::MacOSX;
2626e95d51eSAdrian Prantl case Triple::IOS:
2636e95d51eSAdrian Prantl switch (triple.getEnvironment()) {
2646e95d51eSAdrian Prantl case Triple::MacABI:
2656e95d51eSAdrian Prantl return XcodeSDK::MacOSX;
2666e95d51eSAdrian Prantl case Triple::Simulator:
2676e95d51eSAdrian Prantl return XcodeSDK::iPhoneSimulator;
2686e95d51eSAdrian Prantl default:
2696e95d51eSAdrian Prantl return XcodeSDK::iPhoneOS;
2706e95d51eSAdrian Prantl }
2716e95d51eSAdrian Prantl case Triple::TvOS:
2726e95d51eSAdrian Prantl if (triple.getEnvironment() == Triple::Simulator)
2736e95d51eSAdrian Prantl return XcodeSDK::AppleTVSimulator;
2746e95d51eSAdrian Prantl return XcodeSDK::AppleTVOS;
2756e95d51eSAdrian Prantl case Triple::WatchOS:
2766e95d51eSAdrian Prantl if (triple.getEnvironment() == Triple::Simulator)
2776e95d51eSAdrian Prantl return XcodeSDK::WatchSimulator;
2786e95d51eSAdrian Prantl return XcodeSDK::watchOS;
2796e95d51eSAdrian Prantl case Triple::Linux:
2806e95d51eSAdrian Prantl return XcodeSDK::Linux;
2816e95d51eSAdrian Prantl default:
2826e95d51eSAdrian Prantl return XcodeSDK::unknown;
2836e95d51eSAdrian Prantl }
2846e95d51eSAdrian Prantl }
2853d7b926dSAdrian Prantl
FindXcodeContentsDirectoryInPath(llvm::StringRef path)2863d7b926dSAdrian Prantl std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) {
2873d7b926dSAdrian Prantl auto begin = llvm::sys::path::begin(path);
2883d7b926dSAdrian Prantl auto end = llvm::sys::path::end(path);
2893d7b926dSAdrian Prantl
2903d7b926dSAdrian Prantl // Iterate over the path components until we find something that ends with
2913d7b926dSAdrian Prantl // .app. If the next component is Contents then we've found the Contents
2923d7b926dSAdrian Prantl // directory.
2933d7b926dSAdrian Prantl for (auto it = begin; it != end; ++it) {
2943d7b926dSAdrian Prantl if (it->endswith(".app")) {
2953d7b926dSAdrian Prantl auto next = it;
2963d7b926dSAdrian Prantl if (++next != end && *next == "Contents") {
2973d7b926dSAdrian Prantl llvm::SmallString<128> buffer;
2983d7b926dSAdrian Prantl llvm::sys::path::append(buffer, begin, ++next,
2993d7b926dSAdrian Prantl llvm::sys::path::Style::posix);
3003d7b926dSAdrian Prantl return buffer.str().str();
3013d7b926dSAdrian Prantl }
3023d7b926dSAdrian Prantl }
3033d7b926dSAdrian Prantl }
3043d7b926dSAdrian Prantl
3053d7b926dSAdrian Prantl return {};
3063d7b926dSAdrian Prantl }
307