15ffd83dbSDimitry Andric //===-- XcodeSDK.cpp ------------------------------------------------------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "lldb/Utility/XcodeSDK.h" 105ffd83dbSDimitry Andric #include "lldb/Utility/FileSpec.h" 115ffd83dbSDimitry Andric 125ffd83dbSDimitry Andric #include "lldb/lldb-types.h" 135ffd83dbSDimitry Andric 145ffd83dbSDimitry Andric #include "llvm/ADT/Triple.h" 155ffd83dbSDimitry Andric 165ffd83dbSDimitry Andric #include <string> 175ffd83dbSDimitry Andric 185ffd83dbSDimitry Andric using namespace lldb; 195ffd83dbSDimitry Andric using namespace lldb_private; 205ffd83dbSDimitry Andric 215ffd83dbSDimitry Andric static llvm::StringRef GetName(XcodeSDK::Type type) { 225ffd83dbSDimitry Andric switch (type) { 235ffd83dbSDimitry Andric case XcodeSDK::MacOSX: 245ffd83dbSDimitry Andric return "MacOSX"; 255ffd83dbSDimitry Andric case XcodeSDK::iPhoneSimulator: 265ffd83dbSDimitry Andric return "iPhoneSimulator"; 275ffd83dbSDimitry Andric case XcodeSDK::iPhoneOS: 285ffd83dbSDimitry Andric return "iPhoneOS"; 295ffd83dbSDimitry Andric case XcodeSDK::AppleTVSimulator: 305ffd83dbSDimitry Andric return "AppleTVSimulator"; 315ffd83dbSDimitry Andric case XcodeSDK::AppleTVOS: 325ffd83dbSDimitry Andric return "AppleTVOS"; 335ffd83dbSDimitry Andric case XcodeSDK::WatchSimulator: 345ffd83dbSDimitry Andric return "WatchSimulator"; 355ffd83dbSDimitry Andric case XcodeSDK::watchOS: 365ffd83dbSDimitry Andric return "WatchOS"; 375ffd83dbSDimitry Andric case XcodeSDK::bridgeOS: 385ffd83dbSDimitry Andric return "bridgeOS"; 395ffd83dbSDimitry Andric case XcodeSDK::Linux: 405ffd83dbSDimitry Andric return "Linux"; 415ffd83dbSDimitry Andric case XcodeSDK::unknown: 425ffd83dbSDimitry Andric return {}; 435ffd83dbSDimitry Andric } 445ffd83dbSDimitry Andric llvm_unreachable("Unhandled sdk type!"); 455ffd83dbSDimitry Andric } 465ffd83dbSDimitry Andric 475ffd83dbSDimitry Andric XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) { 485ffd83dbSDimitry Andric if (!m_name.empty()) { 495ffd83dbSDimitry Andric if (!info.version.empty()) 505ffd83dbSDimitry Andric m_name += info.version.getAsString(); 515ffd83dbSDimitry Andric if (info.internal) 525ffd83dbSDimitry Andric m_name += ".Internal"; 535ffd83dbSDimitry Andric m_name += ".sdk"; 545ffd83dbSDimitry Andric } 555ffd83dbSDimitry Andric } 565ffd83dbSDimitry Andric 57*81ad6265SDimitry Andric XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) = default; 585ffd83dbSDimitry Andric 59e8d8bef9SDimitry Andric bool XcodeSDK::operator==(const XcodeSDK &other) { 605ffd83dbSDimitry Andric return m_name == other.m_name; 615ffd83dbSDimitry Andric } 625ffd83dbSDimitry Andric 635ffd83dbSDimitry Andric static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) { 645ffd83dbSDimitry Andric if (name.consume_front("MacOSX")) 655ffd83dbSDimitry Andric return XcodeSDK::MacOSX; 665ffd83dbSDimitry Andric if (name.consume_front("iPhoneSimulator")) 675ffd83dbSDimitry Andric return XcodeSDK::iPhoneSimulator; 685ffd83dbSDimitry Andric if (name.consume_front("iPhoneOS")) 695ffd83dbSDimitry Andric return XcodeSDK::iPhoneOS; 705ffd83dbSDimitry Andric if (name.consume_front("AppleTVSimulator")) 715ffd83dbSDimitry Andric return XcodeSDK::AppleTVSimulator; 725ffd83dbSDimitry Andric if (name.consume_front("AppleTVOS")) 735ffd83dbSDimitry Andric return XcodeSDK::AppleTVOS; 745ffd83dbSDimitry Andric if (name.consume_front("WatchSimulator")) 755ffd83dbSDimitry Andric return XcodeSDK::WatchSimulator; 765ffd83dbSDimitry Andric if (name.consume_front("WatchOS")) 775ffd83dbSDimitry Andric return XcodeSDK::watchOS; 785ffd83dbSDimitry Andric if (name.consume_front("bridgeOS")) 795ffd83dbSDimitry Andric return XcodeSDK::bridgeOS; 805ffd83dbSDimitry Andric if (name.consume_front("Linux")) 815ffd83dbSDimitry Andric return XcodeSDK::Linux; 825ffd83dbSDimitry Andric static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1, 835ffd83dbSDimitry Andric "New SDK type was added, update this list!"); 845ffd83dbSDimitry Andric return XcodeSDK::unknown; 855ffd83dbSDimitry Andric } 865ffd83dbSDimitry Andric 875ffd83dbSDimitry Andric static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) { 885ffd83dbSDimitry Andric unsigned i = 0; 895ffd83dbSDimitry Andric while (i < name.size() && name[i] >= '0' && name[i] <= '9') 905ffd83dbSDimitry Andric ++i; 915ffd83dbSDimitry Andric if (i == name.size() || name[i++] != '.') 925ffd83dbSDimitry Andric return {}; 935ffd83dbSDimitry Andric while (i < name.size() && name[i] >= '0' && name[i] <= '9') 945ffd83dbSDimitry Andric ++i; 955ffd83dbSDimitry Andric if (i == name.size() || name[i++] != '.') 965ffd83dbSDimitry Andric return {}; 975ffd83dbSDimitry Andric 985ffd83dbSDimitry Andric llvm::VersionTuple version; 995ffd83dbSDimitry Andric version.tryParse(name.slice(0, i - 1)); 1005ffd83dbSDimitry Andric name = name.drop_front(i); 1015ffd83dbSDimitry Andric return version; 1025ffd83dbSDimitry Andric } 1035ffd83dbSDimitry Andric 1045ffd83dbSDimitry Andric static bool ParseAppleInternalSDK(llvm::StringRef &name) { 1055ffd83dbSDimitry Andric return name.consume_front("Internal.") || name.consume_front(".Internal."); 1065ffd83dbSDimitry Andric } 1075ffd83dbSDimitry Andric 1085ffd83dbSDimitry Andric XcodeSDK::Info XcodeSDK::Parse() const { 1095ffd83dbSDimitry Andric XcodeSDK::Info info; 1105ffd83dbSDimitry Andric llvm::StringRef input(m_name); 1115ffd83dbSDimitry Andric info.type = ParseSDKName(input); 1125ffd83dbSDimitry Andric info.version = ParseSDKVersion(input); 1135ffd83dbSDimitry Andric info.internal = ParseAppleInternalSDK(input); 1145ffd83dbSDimitry Andric return info; 1155ffd83dbSDimitry Andric } 1165ffd83dbSDimitry Andric 1175ffd83dbSDimitry Andric bool XcodeSDK::IsAppleInternalSDK() const { 1185ffd83dbSDimitry Andric llvm::StringRef input(m_name); 1195ffd83dbSDimitry Andric ParseSDKName(input); 1205ffd83dbSDimitry Andric ParseSDKVersion(input); 1215ffd83dbSDimitry Andric return ParseAppleInternalSDK(input); 1225ffd83dbSDimitry Andric } 1235ffd83dbSDimitry Andric 1245ffd83dbSDimitry Andric llvm::VersionTuple XcodeSDK::GetVersion() const { 1255ffd83dbSDimitry Andric llvm::StringRef input(m_name); 1265ffd83dbSDimitry Andric ParseSDKName(input); 1275ffd83dbSDimitry Andric return ParseSDKVersion(input); 1285ffd83dbSDimitry Andric } 1295ffd83dbSDimitry Andric 1305ffd83dbSDimitry Andric XcodeSDK::Type XcodeSDK::GetType() const { 1315ffd83dbSDimitry Andric llvm::StringRef input(m_name); 1325ffd83dbSDimitry Andric return ParseSDKName(input); 1335ffd83dbSDimitry Andric } 1345ffd83dbSDimitry Andric 1355ffd83dbSDimitry Andric llvm::StringRef XcodeSDK::GetString() const { return m_name; } 1365ffd83dbSDimitry Andric 1375ffd83dbSDimitry Andric bool XcodeSDK::Info::operator<(const Info &other) const { 1385ffd83dbSDimitry Andric return std::tie(type, version, internal) < 1395ffd83dbSDimitry Andric std::tie(other.type, other.version, other.internal); 1405ffd83dbSDimitry Andric } 1415ffd83dbSDimitry Andric 1425ffd83dbSDimitry Andric bool XcodeSDK::Info::operator==(const Info &other) const { 1435ffd83dbSDimitry Andric return std::tie(type, version, internal) == 1445ffd83dbSDimitry Andric std::tie(other.type, other.version, other.internal); 1455ffd83dbSDimitry Andric } 1465ffd83dbSDimitry Andric 147e8d8bef9SDimitry Andric void XcodeSDK::Merge(const XcodeSDK &other) { 1485ffd83dbSDimitry Andric // The "bigger" SDK always wins. 1495ffd83dbSDimitry Andric auto l = Parse(); 1505ffd83dbSDimitry Andric auto r = other.Parse(); 1515ffd83dbSDimitry Andric if (l < r) 1525ffd83dbSDimitry Andric *this = other; 1535ffd83dbSDimitry Andric else { 1545ffd83dbSDimitry Andric // The Internal flag always wins. 1555ffd83dbSDimitry Andric if (llvm::StringRef(m_name).endswith(".sdk")) 1565ffd83dbSDimitry Andric if (!l.internal && r.internal) 1575ffd83dbSDimitry Andric m_name = 1585ffd83dbSDimitry Andric m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk"); 1595ffd83dbSDimitry Andric } 1605ffd83dbSDimitry Andric } 1615ffd83dbSDimitry Andric 1625ffd83dbSDimitry Andric std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) { 1635ffd83dbSDimitry Andric std::string name; 1645ffd83dbSDimitry Andric switch (info.type) { 1655ffd83dbSDimitry Andric case MacOSX: 1665ffd83dbSDimitry Andric name = "macosx"; 1675ffd83dbSDimitry Andric break; 1685ffd83dbSDimitry Andric case iPhoneSimulator: 1695ffd83dbSDimitry Andric name = "iphonesimulator"; 1705ffd83dbSDimitry Andric break; 1715ffd83dbSDimitry Andric case iPhoneOS: 1725ffd83dbSDimitry Andric name = "iphoneos"; 1735ffd83dbSDimitry Andric break; 1745ffd83dbSDimitry Andric case AppleTVSimulator: 1755ffd83dbSDimitry Andric name = "appletvsimulator"; 1765ffd83dbSDimitry Andric break; 1775ffd83dbSDimitry Andric case AppleTVOS: 1785ffd83dbSDimitry Andric name = "appletvos"; 1795ffd83dbSDimitry Andric break; 1805ffd83dbSDimitry Andric case WatchSimulator: 1815ffd83dbSDimitry Andric name = "watchsimulator"; 1825ffd83dbSDimitry Andric break; 1835ffd83dbSDimitry Andric case watchOS: 1845ffd83dbSDimitry Andric name = "watchos"; 1855ffd83dbSDimitry Andric break; 1865ffd83dbSDimitry Andric case bridgeOS: 1875ffd83dbSDimitry Andric name = "bridgeos"; 1885ffd83dbSDimitry Andric break; 1895ffd83dbSDimitry Andric case Linux: 1905ffd83dbSDimitry Andric name = "linux"; 1915ffd83dbSDimitry Andric break; 1925ffd83dbSDimitry Andric case unknown: 1935ffd83dbSDimitry Andric return {}; 1945ffd83dbSDimitry Andric } 1955ffd83dbSDimitry Andric if (!info.version.empty()) 1965ffd83dbSDimitry Andric name += info.version.getAsString(); 1975ffd83dbSDimitry Andric if (info.internal) 1985ffd83dbSDimitry Andric name += ".internal"; 1995ffd83dbSDimitry Andric return name; 2005ffd83dbSDimitry Andric } 2015ffd83dbSDimitry Andric 2025ffd83dbSDimitry Andric bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, 2035ffd83dbSDimitry Andric llvm::VersionTuple version) { 2045ffd83dbSDimitry Andric switch (sdk_type) { 2055ffd83dbSDimitry Andric case Type::MacOSX: 2065ffd83dbSDimitry Andric return version >= llvm::VersionTuple(10, 10); 2075ffd83dbSDimitry Andric case Type::iPhoneOS: 2085ffd83dbSDimitry Andric case Type::iPhoneSimulator: 2095ffd83dbSDimitry Andric case Type::AppleTVOS: 2105ffd83dbSDimitry Andric case Type::AppleTVSimulator: 2115ffd83dbSDimitry Andric return version >= llvm::VersionTuple(8); 2125ffd83dbSDimitry Andric case Type::watchOS: 2135ffd83dbSDimitry Andric case Type::WatchSimulator: 2145ffd83dbSDimitry Andric return version >= llvm::VersionTuple(6); 2155ffd83dbSDimitry Andric default: 2165ffd83dbSDimitry Andric return false; 2175ffd83dbSDimitry Andric } 2185ffd83dbSDimitry Andric 2195ffd83dbSDimitry Andric return false; 2205ffd83dbSDimitry Andric } 2215ffd83dbSDimitry Andric 2225ffd83dbSDimitry Andric bool XcodeSDK::SupportsSwift() const { 2235ffd83dbSDimitry Andric XcodeSDK::Info info = Parse(); 2245ffd83dbSDimitry Andric switch (info.type) { 2255ffd83dbSDimitry Andric case Type::MacOSX: 2265ffd83dbSDimitry Andric return info.version.empty() || info.version >= llvm::VersionTuple(10, 10); 2275ffd83dbSDimitry Andric case Type::iPhoneOS: 2285ffd83dbSDimitry Andric case Type::iPhoneSimulator: 2295ffd83dbSDimitry Andric return info.version.empty() || info.version >= llvm::VersionTuple(8); 2305ffd83dbSDimitry Andric case Type::AppleTVSimulator: 2315ffd83dbSDimitry Andric case Type::AppleTVOS: 2325ffd83dbSDimitry Andric return info.version.empty() || info.version >= llvm::VersionTuple(9); 2335ffd83dbSDimitry Andric case Type::WatchSimulator: 2345ffd83dbSDimitry Andric case Type::watchOS: 2355ffd83dbSDimitry Andric return info.version.empty() || info.version >= llvm::VersionTuple(2); 2365ffd83dbSDimitry Andric case Type::Linux: 2375ffd83dbSDimitry Andric return true; 2385ffd83dbSDimitry Andric default: 2395ffd83dbSDimitry Andric return false; 2405ffd83dbSDimitry Andric } 2415ffd83dbSDimitry Andric } 2425ffd83dbSDimitry Andric 2435ffd83dbSDimitry Andric bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type, 2445ffd83dbSDimitry Andric const FileSpec &sdk_path) { 2455ffd83dbSDimitry Andric ConstString last_path_component = sdk_path.GetLastPathComponent(); 2465ffd83dbSDimitry Andric 2475ffd83dbSDimitry Andric if (!last_path_component) 2485ffd83dbSDimitry Andric return false; 2495ffd83dbSDimitry Andric 2505ffd83dbSDimitry Andric XcodeSDK sdk(last_path_component.GetStringRef().str()); 2515ffd83dbSDimitry Andric if (sdk.GetType() != desired_type) 2525ffd83dbSDimitry Andric return false; 2535ffd83dbSDimitry Andric return SDKSupportsModules(sdk.GetType(), sdk.GetVersion()); 2545ffd83dbSDimitry Andric } 2555ffd83dbSDimitry Andric 2565ffd83dbSDimitry Andric XcodeSDK::Type XcodeSDK::GetSDKTypeForTriple(const llvm::Triple &triple) { 2575ffd83dbSDimitry Andric using namespace llvm; 2585ffd83dbSDimitry Andric switch (triple.getOS()) { 2595ffd83dbSDimitry Andric case Triple::MacOSX: 2605ffd83dbSDimitry Andric case Triple::Darwin: 2615ffd83dbSDimitry Andric return XcodeSDK::MacOSX; 2625ffd83dbSDimitry Andric case Triple::IOS: 2635ffd83dbSDimitry Andric switch (triple.getEnvironment()) { 2645ffd83dbSDimitry Andric case Triple::MacABI: 2655ffd83dbSDimitry Andric return XcodeSDK::MacOSX; 2665ffd83dbSDimitry Andric case Triple::Simulator: 2675ffd83dbSDimitry Andric return XcodeSDK::iPhoneSimulator; 2685ffd83dbSDimitry Andric default: 2695ffd83dbSDimitry Andric return XcodeSDK::iPhoneOS; 2705ffd83dbSDimitry Andric } 2715ffd83dbSDimitry Andric case Triple::TvOS: 2725ffd83dbSDimitry Andric if (triple.getEnvironment() == Triple::Simulator) 2735ffd83dbSDimitry Andric return XcodeSDK::AppleTVSimulator; 2745ffd83dbSDimitry Andric return XcodeSDK::AppleTVOS; 2755ffd83dbSDimitry Andric case Triple::WatchOS: 2765ffd83dbSDimitry Andric if (triple.getEnvironment() == Triple::Simulator) 2775ffd83dbSDimitry Andric return XcodeSDK::WatchSimulator; 2785ffd83dbSDimitry Andric return XcodeSDK::watchOS; 2795ffd83dbSDimitry Andric case Triple::Linux: 2805ffd83dbSDimitry Andric return XcodeSDK::Linux; 2815ffd83dbSDimitry Andric default: 2825ffd83dbSDimitry Andric return XcodeSDK::unknown; 2835ffd83dbSDimitry Andric } 2845ffd83dbSDimitry Andric } 2855ffd83dbSDimitry Andric 2865ffd83dbSDimitry Andric std::string XcodeSDK::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { 2875ffd83dbSDimitry Andric auto begin = llvm::sys::path::begin(path); 2885ffd83dbSDimitry Andric auto end = llvm::sys::path::end(path); 2895ffd83dbSDimitry Andric 2905ffd83dbSDimitry Andric // Iterate over the path components until we find something that ends with 2915ffd83dbSDimitry Andric // .app. If the next component is Contents then we've found the Contents 2925ffd83dbSDimitry Andric // directory. 2935ffd83dbSDimitry Andric for (auto it = begin; it != end; ++it) { 2945ffd83dbSDimitry Andric if (it->endswith(".app")) { 2955ffd83dbSDimitry Andric auto next = it; 2965ffd83dbSDimitry Andric if (++next != end && *next == "Contents") { 2975ffd83dbSDimitry Andric llvm::SmallString<128> buffer; 2985ffd83dbSDimitry Andric llvm::sys::path::append(buffer, begin, ++next, 2995ffd83dbSDimitry Andric llvm::sys::path::Style::posix); 3005ffd83dbSDimitry Andric return buffer.str().str(); 3015ffd83dbSDimitry Andric } 3025ffd83dbSDimitry Andric } 3035ffd83dbSDimitry Andric } 3045ffd83dbSDimitry Andric 3055ffd83dbSDimitry Andric return {}; 3065ffd83dbSDimitry Andric } 307