mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Add -target-min-inlining-version to aid type checking for inlinable functions in resilient libraries
552 lines
18 KiB
C++
552 lines
18 KiB
C++
//===--- Platform.cpp - Implement platform-related helpers ----------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/Platform.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/ADT/Triple.h"
|
|
#include "llvm/Support/VersionTuple.h"
|
|
|
|
using namespace swift;
|
|
|
|
bool swift::tripleIsiOSSimulator(const llvm::Triple &triple) {
|
|
return (triple.isiOS() &&
|
|
!tripleIsMacCatalystEnvironment(triple) &&
|
|
triple.isSimulatorEnvironment());
|
|
}
|
|
|
|
bool swift::tripleIsAppleTVSimulator(const llvm::Triple &triple) {
|
|
return (triple.isTvOS() && triple.isSimulatorEnvironment());
|
|
}
|
|
|
|
bool swift::tripleIsWatchSimulator(const llvm::Triple &triple) {
|
|
return (triple.isWatchOS() && triple.isSimulatorEnvironment());
|
|
}
|
|
|
|
bool swift::tripleIsMacCatalystEnvironment(const llvm::Triple &triple) {
|
|
return triple.isiOS() && !triple.isTvOS() &&
|
|
triple.getEnvironment() == llvm::Triple::MacABI;
|
|
}
|
|
|
|
bool swift::tripleInfersSimulatorEnvironment(const llvm::Triple &triple) {
|
|
switch (triple.getOS()) {
|
|
case llvm::Triple::IOS:
|
|
case llvm::Triple::TvOS:
|
|
case llvm::Triple::WatchOS:
|
|
return !triple.hasEnvironment() &&
|
|
(triple.getArch() == llvm::Triple::x86 ||
|
|
triple.getArch() == llvm::Triple::x86_64) &&
|
|
!tripleIsMacCatalystEnvironment(triple);
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool swift::triplesAreValidForZippering(const llvm::Triple &target,
|
|
const llvm::Triple &targetVariant) {
|
|
// The arch and vendor must match.
|
|
if (target.getArchName() != targetVariant.getArchName() ||
|
|
target.getArch() != targetVariant.getArch() ||
|
|
target.getSubArch() != targetVariant.getSubArch() ||
|
|
target.getVendor() != targetVariant.getVendor()) {
|
|
return false;
|
|
}
|
|
|
|
// Allow a macOS target and an iOS-macabi target variant
|
|
// This is typically the case when zippering a library originally
|
|
// developed for macOS.
|
|
if (target.isMacOSX() && tripleIsMacCatalystEnvironment(targetVariant)) {
|
|
return true;
|
|
}
|
|
|
|
// Allow an iOS-macabi target and a macOS target variant. This would
|
|
// be the case when zippering a library originally developed for
|
|
// iOS.
|
|
if (targetVariant.isMacOSX() && tripleIsMacCatalystEnvironment(target)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const Optional<llvm::VersionTuple>
|
|
swift::minimumABIStableOSVersionForTriple(const llvm::Triple &triple) {
|
|
if (triple.isMacOSX())
|
|
return llvm::VersionTuple(10, 14, 4);
|
|
|
|
if (triple.isiOS() /* including tvOS */)
|
|
return llvm::VersionTuple(12, 2);
|
|
|
|
if (triple.isWatchOS())
|
|
return llvm::VersionTuple(5, 2);
|
|
|
|
return None;
|
|
}
|
|
|
|
bool swift::tripleRequiresRPathForSwiftLibrariesInOS(
|
|
const llvm::Triple &triple) {
|
|
if (triple.isMacOSX()) {
|
|
// macOS versions before 10.14.4 don't have Swift in the OS
|
|
// (the linker still uses an rpath-based install name until 10.15).
|
|
// macOS versions before 12.0 don't have _Concurrency in the OS.
|
|
return triple.isMacOSXVersionLT(12, 0);
|
|
}
|
|
|
|
if (triple.isiOS()) {
|
|
// iOS versions before 12.2 don't have Swift in the OS.
|
|
// iOS versions before 15.0 don't have _Concurrency in the OS.
|
|
return triple.isOSVersionLT(15, 0);
|
|
}
|
|
|
|
if (triple.isWatchOS()) {
|
|
// watchOS versions before 5.2 don't have Swift in the OS.
|
|
// watchOS versions before 8.0 don't have _Concurrency in the OS.
|
|
return triple.isOSVersionLT(8, 0);
|
|
}
|
|
|
|
// Other platforms don't have Swift installed as part of the OS by default.
|
|
return false;
|
|
}
|
|
|
|
DarwinPlatformKind swift::getDarwinPlatformKind(const llvm::Triple &triple) {
|
|
if (triple.isiOS()) {
|
|
if (triple.isTvOS()) {
|
|
if (tripleIsAppleTVSimulator(triple))
|
|
return DarwinPlatformKind::TvOSSimulator;
|
|
return DarwinPlatformKind::TvOS;
|
|
}
|
|
|
|
if (tripleIsiOSSimulator(triple))
|
|
return DarwinPlatformKind::IPhoneOSSimulator;
|
|
return DarwinPlatformKind::IPhoneOS;
|
|
}
|
|
|
|
if (triple.isWatchOS()) {
|
|
if (tripleIsWatchSimulator(triple))
|
|
return DarwinPlatformKind::WatchOSSimulator;
|
|
return DarwinPlatformKind::WatchOS;
|
|
}
|
|
|
|
if (triple.isMacOSX())
|
|
return DarwinPlatformKind::MacOS;
|
|
|
|
llvm_unreachable("Unsupported Darwin platform");
|
|
}
|
|
|
|
static StringRef getPlatformNameForDarwin(const DarwinPlatformKind platform) {
|
|
switch (platform) {
|
|
case DarwinPlatformKind::MacOS:
|
|
return "macosx";
|
|
case DarwinPlatformKind::IPhoneOS:
|
|
return "iphoneos";
|
|
case DarwinPlatformKind::IPhoneOSSimulator:
|
|
return "iphonesimulator";
|
|
case DarwinPlatformKind::TvOS:
|
|
return "appletvos";
|
|
case DarwinPlatformKind::TvOSSimulator:
|
|
return "appletvsimulator";
|
|
case DarwinPlatformKind::WatchOS:
|
|
return "watchos";
|
|
case DarwinPlatformKind::WatchOSSimulator:
|
|
return "watchsimulator";
|
|
}
|
|
llvm_unreachable("Unsupported Darwin platform");
|
|
}
|
|
|
|
StringRef swift::getPlatformNameForTriple(const llvm::Triple &triple) {
|
|
switch (triple.getOS()) {
|
|
case llvm::Triple::UnknownOS:
|
|
llvm_unreachable("unknown OS");
|
|
case llvm::Triple::ZOS:
|
|
case llvm::Triple::Ananas:
|
|
case llvm::Triple::CloudABI:
|
|
case llvm::Triple::DragonFly:
|
|
case llvm::Triple::Emscripten:
|
|
case llvm::Triple::Fuchsia:
|
|
case llvm::Triple::KFreeBSD:
|
|
case llvm::Triple::Lv2:
|
|
case llvm::Triple::NetBSD:
|
|
case llvm::Triple::Solaris:
|
|
case llvm::Triple::Minix:
|
|
case llvm::Triple::RTEMS:
|
|
case llvm::Triple::NaCl:
|
|
case llvm::Triple::AIX:
|
|
case llvm::Triple::CUDA:
|
|
case llvm::Triple::NVCL:
|
|
case llvm::Triple::AMDHSA:
|
|
case llvm::Triple::ELFIAMCU:
|
|
case llvm::Triple::Mesa3D:
|
|
case llvm::Triple::Contiki:
|
|
case llvm::Triple::AMDPAL:
|
|
case llvm::Triple::HermitCore:
|
|
case llvm::Triple::Hurd:
|
|
return "";
|
|
case llvm::Triple::Darwin:
|
|
case llvm::Triple::MacOSX:
|
|
case llvm::Triple::IOS:
|
|
case llvm::Triple::TvOS:
|
|
case llvm::Triple::WatchOS:
|
|
return getPlatformNameForDarwin(getDarwinPlatformKind(triple));
|
|
case llvm::Triple::Linux:
|
|
return triple.isAndroid() ? "android" : "linux";
|
|
case llvm::Triple::FreeBSD:
|
|
return "freebsd";
|
|
case llvm::Triple::OpenBSD:
|
|
return "openbsd";
|
|
case llvm::Triple::Win32:
|
|
switch (triple.getEnvironment()) {
|
|
case llvm::Triple::Cygnus:
|
|
return "cygwin";
|
|
case llvm::Triple::GNU:
|
|
return "mingw";
|
|
case llvm::Triple::MSVC:
|
|
case llvm::Triple::Itanium:
|
|
return "windows";
|
|
default:
|
|
llvm_unreachable("unsupported Windows environment");
|
|
}
|
|
case llvm::Triple::PS4:
|
|
return "ps4";
|
|
case llvm::Triple::Haiku:
|
|
return "haiku";
|
|
case llvm::Triple::WASI:
|
|
return "wasi";
|
|
}
|
|
llvm_unreachable("unsupported OS");
|
|
}
|
|
|
|
StringRef swift::getMajorArchitectureName(const llvm::Triple &Triple) {
|
|
if (Triple.isOSLinux()) {
|
|
switch (Triple.getSubArch()) {
|
|
case llvm::Triple::SubArchType::ARMSubArch_v7:
|
|
return "armv7";
|
|
case llvm::Triple::SubArchType::ARMSubArch_v6:
|
|
return "armv6";
|
|
case llvm::Triple::SubArchType::ARMSubArch_v5:
|
|
return "armv5";
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return Triple.getArchName();
|
|
}
|
|
|
|
// The code below is responsible for normalizing target triples into the form
|
|
// used to name target-specific swiftmodule, swiftinterface, and swiftdoc files.
|
|
// If two triples have incompatible ABIs or can be distinguished by Swift #if
|
|
// declarations, they should normalize to different values.
|
|
//
|
|
// This code is only really used on platforms with toolchains supporting fat
|
|
// binaries (a single binary containing multiple architectures). On these
|
|
// platforms, this code should strip unnecessary details from target triple
|
|
// components and map synonyms to canonical values. Even values which don't need
|
|
// any special canonicalization should be documented here as comments.
|
|
//
|
|
// (Fallback behavior does not belong here; it should be implemented in code
|
|
// that calls this function, most importantly in SerializedModuleLoaderBase.)
|
|
//
|
|
// If you're trying to refer to this code to understand how Swift behaves and
|
|
// you're unfamiliar with LLVM internals, here's a cheat sheet for reading it:
|
|
//
|
|
// * llvm::Triple is the type for a target name. It's a bit of a misnomer,
|
|
// because it can contain three or four values: arch-vendor-os[-environment].
|
|
//
|
|
// * In .Cases and .Case, the last argument is the value the arguments before it
|
|
// map to. That is, `.Cases("bar", "baz", "foo")` will return "foo" if it sees
|
|
// "bar" or "baz".
|
|
//
|
|
// * llvm::Optional is similar to a Swift Optional: it either contains a value
|
|
// or represents the absence of one. `None` is equivalent to `nil`; leading
|
|
// `*` is equivalent to trailing `!`; conversion to `bool` is a not-`None`
|
|
// check.
|
|
|
|
static StringRef
|
|
getArchForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) {
|
|
auto tripleArchName = triple.getArchName();
|
|
|
|
return llvm::StringSwitch<StringRef>(tripleArchName)
|
|
.Cases("arm64", "aarch64", "arm64")
|
|
.Cases("arm64_32", "aarch64_32", "arm64_32")
|
|
.Cases("x86_64", "amd64", "x86_64")
|
|
.Cases("i386", "i486", "i586", "i686", "i786", "i886", "i986",
|
|
"i386")
|
|
.Cases("unknown", "", "unknown")
|
|
// These values are also supported, but are handled by the default case below:
|
|
// .Case ("armv7s", "armv7s")
|
|
// .Case ("armv7k", "armv7k")
|
|
// .Case ("armv7", "armv7")
|
|
// .Case ("arm64e", "arm64e")
|
|
.Default(tripleArchName);
|
|
}
|
|
|
|
static StringRef
|
|
getVendorForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) {
|
|
// We unconditionally normalize to "apple" because it's relatively common for
|
|
// build systems to omit the vendor name or use an incorrect one like
|
|
// "unknown". Most parts of the compiler ignore the vendor, so you might not
|
|
// notice such a mistake.
|
|
//
|
|
// Please don't depend on this behavior--specify 'apple' if you're building
|
|
// for an Apple platform.
|
|
|
|
assert(triple.isOSDarwin() &&
|
|
"shouldn't normalize non-Darwin triple to 'apple'");
|
|
|
|
return "apple";
|
|
}
|
|
|
|
static StringRef
|
|
getOSForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) {
|
|
auto tripleOSName = triple.getOSName();
|
|
|
|
// Truncate the OS name before the first digit. "Digit" here is ASCII '0'-'9'.
|
|
auto tripleOSNameNoVersion = tripleOSName.take_until(llvm::isDigit);
|
|
|
|
return llvm::StringSwitch<StringRef>(tripleOSNameNoVersion)
|
|
.Cases("macos", "macosx", "darwin", "macos")
|
|
.Cases("unknown", "", "unknown")
|
|
// These values are also supported, but are handled by the default case below:
|
|
// .Case ("ios", "ios")
|
|
// .Case ("tvos", "tvos")
|
|
// .Case ("watchos", "watchos")
|
|
.Default(tripleOSNameNoVersion);
|
|
}
|
|
|
|
static Optional<StringRef>
|
|
getEnvironmentForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) {
|
|
auto tripleEnvironment = triple.getEnvironmentName();
|
|
return llvm::StringSwitch<Optional<StringRef>>(tripleEnvironment)
|
|
.Cases("unknown", "", None)
|
|
// These values are also supported, but are handled by the default case below:
|
|
// .Case ("simulator", StringRef("simulator"))
|
|
// .Case ("macabi", StringRef("macabi"))
|
|
.Default(tripleEnvironment);
|
|
}
|
|
|
|
llvm::Triple swift::getTargetSpecificModuleTriple(const llvm::Triple &triple) {
|
|
// isOSDarwin() returns true for all Darwin-style OSes, including macOS, iOS,
|
|
// etc.
|
|
if (triple.isOSDarwin()) {
|
|
StringRef newArch = getArchForAppleTargetSpecificModuleTriple(triple);
|
|
|
|
StringRef newVendor = getVendorForAppleTargetSpecificModuleTriple(triple);
|
|
|
|
StringRef newOS = getOSForAppleTargetSpecificModuleTriple(triple);
|
|
|
|
Optional<StringRef> newEnvironment =
|
|
getEnvironmentForAppleTargetSpecificModuleTriple(triple);
|
|
|
|
if (!newEnvironment)
|
|
// Generate an arch-vendor-os triple.
|
|
return llvm::Triple(newArch, newVendor, newOS);
|
|
|
|
// Generate an arch-vendor-os-environment triple.
|
|
return llvm::Triple(newArch, newVendor, newOS, *newEnvironment);
|
|
}
|
|
|
|
// android - drop the API level. That is not pertinent to the module; the API
|
|
// availability is handled by the clang importer.
|
|
if (triple.isAndroid()) {
|
|
StringRef environment =
|
|
llvm::Triple::getEnvironmentTypeName(triple.getEnvironment());
|
|
|
|
return llvm::Triple(triple.getArchName(), triple.getVendorName(),
|
|
triple.getOSName(), environment);
|
|
}
|
|
|
|
// Other platforms get no normalization.
|
|
return triple;
|
|
}
|
|
|
|
llvm::Triple swift::getUnversionedTriple(const llvm::Triple &triple) {
|
|
StringRef unversionedOSName = triple.getOSName().take_until(llvm::isDigit);
|
|
if (triple.getEnvironment()) {
|
|
StringRef environment =
|
|
llvm::Triple::getEnvironmentTypeName(triple.getEnvironment());
|
|
|
|
return llvm::Triple(triple.getArchName(), triple.getVendorName(),
|
|
unversionedOSName, environment);
|
|
}
|
|
|
|
return llvm::Triple(triple.getArchName(), triple.getVendorName(),
|
|
unversionedOSName);
|
|
}
|
|
|
|
Optional<llvm::VersionTuple>
|
|
swift::getSwiftRuntimeCompatibilityVersionForTarget(
|
|
const llvm::Triple &Triple) {
|
|
unsigned Major, Minor, Micro;
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
|
|
if (Triple.isMacOSX()) {
|
|
Triple.getMacOSXVersion(Major, Minor, Micro);
|
|
|
|
auto floorFor64 = [&Triple](llvm::VersionTuple v) {
|
|
if (!Triple.isAArch64()) return v;
|
|
// macOS got first arm64(e) support in 11.0, i.e. VersionTuple(5, 3)
|
|
return MAX(v, llvm::VersionTuple(5, 3));
|
|
};
|
|
|
|
if (Major == 10) {
|
|
if (Triple.isAArch64() && Minor <= 16)
|
|
return floorFor64(llvm::VersionTuple(5, 3));
|
|
|
|
if (Minor <= 14) {
|
|
return floorFor64(llvm::VersionTuple(5, 0));
|
|
} else if (Minor <= 15) {
|
|
if (Micro <= 3) {
|
|
return floorFor64(llvm::VersionTuple(5, 1));
|
|
} else {
|
|
return floorFor64(llvm::VersionTuple(5, 2));
|
|
}
|
|
}
|
|
} else if (Major == 11) {
|
|
if (Minor <= 3)
|
|
return floorFor64(llvm::VersionTuple(5, 3));
|
|
|
|
return floorFor64(llvm::VersionTuple(5, 4));
|
|
} else if (Major == 12) {
|
|
return floorFor64(llvm::VersionTuple(5, 5));
|
|
}
|
|
} else if (Triple.isiOS()) { // includes tvOS
|
|
Triple.getiOSVersion(Major, Minor, Micro);
|
|
|
|
auto floorForArchitecture = [&Triple, Major](llvm::VersionTuple v) {
|
|
// arm64 simulators and macCatalyst are introduced in iOS 14.0/tvOS 14.0
|
|
// with Swift 5.3
|
|
if (Triple.isAArch64() && Major <= 14 &&
|
|
(Triple.isSimulatorEnvironment() ||
|
|
Triple.isMacCatalystEnvironment()))
|
|
return MAX(v, llvm::VersionTuple(5, 3));
|
|
|
|
if (Triple.getArchName() != "arm64e") return v;
|
|
|
|
// iOS got first arm64e support in 12.0, which has a Swift runtime version
|
|
// older than 5.0, so let's floor at VersionTuple(5, 0) instead.
|
|
return MAX(v, llvm::VersionTuple(5, 0));
|
|
};
|
|
|
|
if (Major <= 12) {
|
|
return floorForArchitecture(llvm::VersionTuple(5, 0));
|
|
} else if (Major <= 13) {
|
|
if (Minor <= 3) {
|
|
return floorForArchitecture(llvm::VersionTuple(5, 1));
|
|
} else {
|
|
return floorForArchitecture(llvm::VersionTuple(5, 2));
|
|
}
|
|
} else if (Major <= 14) {
|
|
if (Minor <= 4)
|
|
return floorForArchitecture(llvm::VersionTuple(5, 3));
|
|
|
|
return floorForArchitecture(llvm::VersionTuple(5, 4));
|
|
} else if (Major <= 15) {
|
|
return floorForArchitecture(llvm::VersionTuple(5, 5));
|
|
}
|
|
} else if (Triple.isWatchOS()) {
|
|
auto floorFor64bits = [&Triple](llvm::VersionTuple v) {
|
|
if (!Triple.isArch64Bit()) return v;
|
|
// 64-bit watchOS was introduced with Swift 5.3
|
|
return MAX(v, llvm::VersionTuple(5, 3));
|
|
};
|
|
|
|
Triple.getWatchOSVersion(Major, Minor, Micro);
|
|
if (Major <= 5) {
|
|
return floorFor64bits(llvm::VersionTuple(5, 0));
|
|
} else if (Major <= 6) {
|
|
if (Minor <= 1) {
|
|
return floorFor64bits(llvm::VersionTuple(5, 1));
|
|
} else {
|
|
return floorFor64bits(llvm::VersionTuple(5, 2));
|
|
}
|
|
} else if (Major <= 7) {
|
|
if (Minor <= 4)
|
|
return floorFor64bits(llvm::VersionTuple(5, 3));
|
|
|
|
return floorFor64bits(llvm::VersionTuple(5, 4));
|
|
} else if (Major <= 8) {
|
|
return floorFor64bits(llvm::VersionTuple(5, 5));
|
|
}
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
static const llvm::VersionTuple minimumMacCatalystDeploymentTarget() {
|
|
return llvm::VersionTuple(13, 1);
|
|
}
|
|
|
|
llvm::VersionTuple swift::getTargetSDKVersion(clang::DarwinSDKInfo &SDKInfo,
|
|
const llvm::Triple &triple) {
|
|
// Retrieve the SDK version.
|
|
auto SDKVersion = SDKInfo.getVersion();
|
|
|
|
// For the Mac Catalyst environment, we have a macOS SDK with a macOS
|
|
// SDK version. Map that to the corresponding iOS version number to pass
|
|
// down to the linker.
|
|
if (tripleIsMacCatalystEnvironment(triple)) {
|
|
if (const auto *MacOStoMacCatalystMapping = SDKInfo.getVersionMapping(
|
|
clang::DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
|
|
return MacOStoMacCatalystMapping
|
|
->map(SDKVersion, minimumMacCatalystDeploymentTarget(), None)
|
|
.getValueOr(llvm::VersionTuple(0, 0, 0));
|
|
}
|
|
return llvm::VersionTuple(0, 0, 0);
|
|
}
|
|
|
|
return SDKVersion;
|
|
}
|
|
|
|
static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) {
|
|
auto BufOrErr = llvm::MemoryBuffer::getFile(Path);
|
|
if (!BufOrErr) {
|
|
// FIXME: diagnose properly
|
|
return {};
|
|
}
|
|
|
|
std::string Key = "<key>";
|
|
Key += KeyName;
|
|
Key += "</key>";
|
|
|
|
StringRef Lines = BufOrErr.get()->getBuffer();
|
|
while (!Lines.empty()) {
|
|
StringRef CurLine;
|
|
std::tie(CurLine, Lines) = Lines.split('\n');
|
|
if (CurLine.find(Key) != StringRef::npos) {
|
|
std::tie(CurLine, Lines) = Lines.split('\n');
|
|
unsigned Begin = CurLine.find("<string>") + strlen("<string>");
|
|
unsigned End = CurLine.find("</string>");
|
|
return CurLine.substr(Begin, End - Begin).str();
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
std::string swift::getSDKBuildVersionFromPlist(StringRef Path) {
|
|
return getPlistEntry(Path, "ProductBuildVersion");
|
|
}
|
|
|
|
std::string swift::getSDKBuildVersion(StringRef Path) {
|
|
return getSDKBuildVersionFromPlist((llvm::Twine(Path) +
|
|
"/System/Library/CoreServices/SystemVersion.plist").str());
|
|
}
|
|
|
|
std::string swift::getSDKName(StringRef Path) {
|
|
std::string Name = getPlistEntry(llvm::Twine(Path)+"/SDKSettings.plist",
|
|
"CanonicalName");
|
|
if (Name.empty() && Path.endswith(".sdk")) {
|
|
Name = llvm::sys::path::filename(Path).drop_back(strlen(".sdk")).str();
|
|
}
|
|
return Name;
|
|
}
|