1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2014-2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Basics
import class Basics.AsyncProcess
public struct MinimumDeploymentTarget {
private struct MinimumDeploymentTargetKey: Hashable {
let binaryPath: AbsolutePath
let platform: PackageModel.Platform
}
private let minimumDeploymentTargets = ThreadSafeKeyValueStore<MinimumDeploymentTargetKey,PlatformVersion>()
private let xcTestMinimumDeploymentTargets = ThreadSafeKeyValueStore<PackageModel.Platform,PlatformVersion>()
public static let `default`: MinimumDeploymentTarget = .init()
private init() {
}
public func computeMinimumDeploymentTarget(of binaryPath: AbsolutePath, platform: PackageModel.Platform) throws -> PlatformVersion {
try self.minimumDeploymentTargets.memoize(MinimumDeploymentTargetKey(binaryPath: binaryPath, platform: platform)) {
return try Self.computeMinimumDeploymentTarget(of: binaryPath, platform: platform) ?? platform.oldestSupportedVersion
}
}
public func computeXCTestMinimumDeploymentTarget(for platform: PackageModel.Platform) -> PlatformVersion {
self.xcTestMinimumDeploymentTargets.memoize(platform) {
return Self.computeXCTestMinimumDeploymentTarget(for: platform)
}
}
static func computeMinimumDeploymentTarget(of binaryPath: AbsolutePath, platform: PackageModel.Platform) throws -> PlatformVersion? {
guard let (_, platformName) = platform.sdkNameAndPlatform else {
return nil
}
let runResult = try AsyncProcess.popen(arguments: ["/usr/bin/xcrun", "vtool", "-show-build", binaryPath.pathString])
var lines = try runResult.utf8Output().components(separatedBy: "\n")
while !lines.isEmpty {
let first = lines.removeFirst()
if first.contains("platform \(platformName)"), let line = lines.first, line.contains("minos") {
return line.components(separatedBy: " ").last.map(PlatformVersion.init(stringLiteral:))
}
}
return nil
}
static func computeXCTestMinimumDeploymentTarget(with runResult: AsyncProcessResult, platform: PackageModel.Platform) throws -> PlatformVersion? {
guard let output = try runResult.utf8Output().spm_chuzzle() else { return nil }
let sdkPath = try AbsolutePath(validating: output)
let xcTestPath = try AbsolutePath(validating: "Developer/Library/Frameworks/XCTest.framework/XCTest", relativeTo: sdkPath)
return try computeMinimumDeploymentTarget(of: xcTestPath, platform: platform)
}
static func computeXCTestMinimumDeploymentTarget(for platform: PackageModel.Platform) -> PlatformVersion {
guard let (sdkName, _) = platform.sdkNameAndPlatform else {
return platform.oldestSupportedVersion
}
// On macOS, we are determining the deployment target by looking at the XCTest binary.
#if os(macOS)
do {
let runResult = try AsyncProcess.popen(arguments: ["/usr/bin/xcrun", "--sdk", sdkName, "--show-sdk-platform-path"])
if let version = try computeXCTestMinimumDeploymentTarget(with: runResult, platform: platform) {
return version
}
} catch { } // we do not treat this a fatal and instead use the fallback minimum deployment target
#endif
return platform.oldestSupportedVersion
}
}
private extension PackageModel.Platform {
var sdkNameAndPlatform: (String, String)? {
switch self {
case .macOS:
return ("macosx", "MACOS")
case .macCatalyst:
return ("macosx", "MACCATALYST")
case .iOS:
return ("iphoneos", "IOS")
case .tvOS:
return ("appletvos", "TVOS")
case .watchOS:
return ("watchos", "WATCHOS")
case .visionOS:
return ("xros", "XROS")
case .driverKit:
return nil // DriverKit does not support XCTest.
default:
return nil
}
}
}
|