Skip to content

Implicitly support Darwin SDKs on macOS #6828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9aa5ee8
Implicitly support all Darwin triples on macOS
kabiroberai Aug 16, 2023
b82a400
comment
kabiroberai Aug 18, 2023
ca0822d
Fix sdkPlatformFrameworkPath memoization
kabiroberai Aug 18, 2023
a202320
Add tests
kabiroberai Aug 18, 2023
46b65d1
a dash of determinism
kabiroberai Aug 18, 2023
d253fab
Feedback
kabiroberai Aug 19, 2023
ba32e4c
We can't run cross-compiled tests yet
kabiroberai Aug 19, 2023
b273ba4
test suite -> tests
kabiroberai Aug 19, 2023
2f9adad
Reintroduce tuple API as deprecated
kabiroberai Aug 19, 2023
9e51703
Set targetTriple for systemSwiftSDK
kabiroberai Aug 22, 2023
ed1513e
Allow default SDKs via --swift-sdk
kabiroberai Aug 22, 2023
c62ad42
feedback
kabiroberai Sep 8, 2023
6d89477
Merge branch 'main' into darwin-target-sdks
kabiroberai Aug 28, 2024
c7c6e4f
fixup
kabiroberai Aug 28, 2024
4633c7f
tweaks
kabiroberai Aug 28, 2024
c610dc8
remove commented code
kabiroberai Aug 28, 2024
7e9d820
public
kabiroberai Aug 28, 2024
78bed58
Add another test
kabiroberai Aug 28, 2024
0b09cb1
Move SPI change into a separate PR
kabiroberai Aug 28, 2024
88fb22b
Merge branch 'main' into darwin-target-sdks
kabiroberai Aug 30, 2024
b6870b3
Support platform-specific SDKROOT
kabiroberai Aug 30, 2024
c2e9cca
more env vars
kabiroberai Aug 31, 2024
5560fd3
potential fixes
kabiroberai Sep 2, 2024
79f582d
fix warning
kabiroberai Sep 2, 2024
3fe9ac7
drop xctest platform checks
kabiroberai Sep 2, 2024
24cfc46
use xcrunName for platformPath
kabiroberai Sep 2, 2024
8351d14
Use xcrunName for platform path override as well
kabiroberai Sep 4, 2024
bb4f49c
Merge branch 'main' into darwin-target-sdks
kabiroberai Oct 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Sources/Commands/Utilities/TestingSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,11 @@ enum TestingSupport {
return env
#else
// Add the sdk platform path if we have it.
if let sdkPlatformFrameworksPath = try? SwiftSDK.sdkPlatformFrameworkPaths() {
// Since XCTestHelper targets macOS, we need the macOS platform paths here.
if let sdkPlatformPaths = try? SwiftSDK.sdkPlatformPaths(for: .macOS) {
// appending since we prefer the user setting (if set) to the one we inject
env.appendPath(key: "DYLD_FRAMEWORK_PATH", value: sdkPlatformFrameworksPath.fwk.pathString)
env.appendPath(key: "DYLD_LIBRARY_PATH", value: sdkPlatformFrameworksPath.lib.pathString)
env.appendPath(key: "DYLD_FRAMEWORK_PATH", value: sdkPlatformPaths.frameworks.pathString)
env.appendPath(key: "DYLD_LIBRARY_PATH", value: sdkPlatformPaths.libraries.pathString)
}

// We aren't using XCTest's harness logic to run Swift Testing tests.
Expand Down
135 changes: 106 additions & 29 deletions Sources/PackageModel/SwiftSDKs/SwiftSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,25 @@ public struct SwiftSDK: Equatable {
environment: Environment = .current,
observabilityScope: ObservabilityScope? = nil,
fileSystem: any FileSystem = localFileSystem
) throws -> SwiftSDK {
try self.systemSwiftSDK(
binDir,
environment: environment,
observabilityScope: observabilityScope,
fileSystem: fileSystem
)
}

/// A default Swift SDK on the host.
///
/// Equivalent to `hostSwiftSDK`, except on macOS, where passing a non-nil `darwinPlatformOverride`
/// will result in the SDK for the corresponding Darwin platform.
private static func systemSwiftSDK(
_ binDir: AbsolutePath? = nil,
environment: Environment = .current,
observabilityScope: ObservabilityScope? = nil,
fileSystem: any FileSystem = localFileSystem,
darwinPlatformOverride: DarwinPlatform? = nil
) throws -> SwiftSDK {
// Select the correct binDir.
if environment["SWIFTPM_CUSTOM_BINDIR"] != nil {
Expand All @@ -535,13 +554,16 @@ public struct SwiftSDK: Equatable {

let sdkPath: AbsolutePath?
#if os(macOS)
let darwinPlatform = darwinPlatformOverride ?? .macOS
// Get the SDK.
if let value = environment["SDKROOT"] {
sdkPath = try AbsolutePath(validating: value)
} else if let value = environment[EnvironmentKey("SWIFTPM_SDKROOT_\(darwinPlatform.xcrunName)")] {
sdkPath = try AbsolutePath(validating: value)
} else {
// No value in env, so search for it.
let sdkPathStr = try AsyncProcess.checkNonZeroExit(
arguments: ["/usr/bin/xcrun", "--sdk", "macosx", "--show-sdk-path"],
arguments: ["/usr/bin/xcrun", "--sdk", darwinPlatform.xcrunName, "--show-sdk-path"],
environment: environment
).spm_chomp()
guard !sdkPathStr.isEmpty else {
Expand All @@ -559,11 +581,11 @@ public struct SwiftSDK: Equatable {
var extraSwiftCFlags: [String] = []
#if os(macOS)
do {
let sdkPaths = try SwiftSDK.sdkPlatformFrameworkPaths(environment: environment)
extraCCFlags += ["-F", sdkPaths.fwk.pathString]
extraSwiftCFlags += ["-F", sdkPaths.fwk.pathString]
extraSwiftCFlags += ["-I", sdkPaths.lib.pathString]
extraSwiftCFlags += ["-L", sdkPaths.lib.pathString]
let sdkPaths = try SwiftSDK.sdkPlatformPaths(for: darwinPlatform, environment: environment)
extraCCFlags += ["-F", sdkPaths.frameworks.pathString]
extraSwiftCFlags += ["-F", sdkPaths.frameworks.pathString]
extraSwiftCFlags += ["-I", sdkPaths.libraries.pathString]
extraSwiftCFlags += ["-L", sdkPaths.libraries.pathString]
xctestSupport = .supported
} catch {
xctestSupport = .unsupported(reason: String(describing: error))
Expand All @@ -589,15 +611,40 @@ public struct SwiftSDK: Equatable {
)
}

/// Auxiliary platform frameworks and libraries.
///
/// The referenced directories may contain, for example, test support utilities.
///
/// - SeeAlso: ``sdkPlatformPaths(for:environment:)``
public struct PlatformPaths {
/// Path to the directory containing auxiliary platform frameworks.
public var frameworks: AbsolutePath

/// Path to the directory containing auxiliary platform libraries.
public var libraries: AbsolutePath
}

/// Returns `macosx` sdk platform framework path.
@available(*, deprecated, message: "use sdkPlatformPaths(for:) instead")
public static func sdkPlatformFrameworkPaths(
environment: Environment = .current
) throws -> (fwk: AbsolutePath, lib: AbsolutePath) {
if let path = _sdkPlatformFrameworkPath {
let paths = try sdkPlatformPaths(for: .macOS, environment: environment)
return (fwk: paths.frameworks, lib: paths.libraries)
}

/// Returns ``SwiftSDK/PlatformPaths`` for the provided Darwin platform.
public static func sdkPlatformPaths(
for darwinPlatform: DarwinPlatform,
environment: Environment = .current
) throws -> PlatformPaths {
if let path = _sdkPlatformFrameworkPath[darwinPlatform] {
return path
}
let platformPath = try AsyncProcess.checkNonZeroExit(
arguments: ["/usr/bin/xcrun", "--sdk", "macosx", "--show-sdk-platform-path"],
let platformPath = try environment[
EnvironmentKey("SWIFTPM_PLATFORM_PATH_\(darwinPlatform.xcrunName)")
] ?? AsyncProcess.checkNonZeroExit(
arguments: ["/usr/bin/xcrun", "--sdk", darwinPlatform.xcrunName, "--show-sdk-platform-path"],
environment: environment
).spm_chomp()

Expand All @@ -615,33 +662,26 @@ public struct SwiftSDK: Equatable {
components: "Developer", "usr", "lib"
)

let sdkPlatformFrameworkPath = (fwk, lib)
_sdkPlatformFrameworkPath = sdkPlatformFrameworkPath
let sdkPlatformFrameworkPath = PlatformPaths(frameworks: fwk, libraries: lib)
_sdkPlatformFrameworkPath[darwinPlatform] = sdkPlatformFrameworkPath
return sdkPlatformFrameworkPath
}

// FIXME: convert this from a tuple to a proper struct with documented properties
/// Cache storage for sdk platform path.
private static var _sdkPlatformFrameworkPath: (fwk: AbsolutePath, lib: AbsolutePath)? = nil
/// Cache storage for sdk platform paths.
private static var _sdkPlatformFrameworkPath: [DarwinPlatform: PlatformPaths] = [:]

/// Returns a default Swift SDK for a given target environment
@available(*, deprecated, renamed: "defaultSwiftSDK")
public static func defaultDestination(for triple: Triple, host: SwiftSDK) -> SwiftSDK? {
if triple.isWASI() {
let wasiSysroot = host.toolset.rootPaths.first?
.parentDirectory // usr
.appending(components: "share", "wasi-sysroot")
return SwiftSDK(
targetTriple: triple,
toolset: host.toolset,
pathsConfiguration: .init(sdkRootPath: wasiSysroot)
)
}
return nil
defaultSwiftSDK(for: triple, hostSDK: host)
}

/// Returns a default Swift SDK of a given target environment.
public static func defaultSwiftSDK(for targetTriple: Triple, hostSDK: SwiftSDK) -> SwiftSDK? {
public static func defaultSwiftSDK(
for targetTriple: Triple,
hostSDK: SwiftSDK,
environment: Environment = .current
) -> SwiftSDK? {
if targetTriple.isWASI() {
let wasiSysroot = hostSDK.toolset.rootPaths.first?
.parentDirectory // usr
Expand All @@ -652,6 +692,20 @@ public struct SwiftSDK: Equatable {
pathsConfiguration: .init(sdkRootPath: wasiSysroot)
)
}

#if os(macOS)
if let darwinPlatform = targetTriple.darwinPlatform {
// the Darwin SDKs are trivially available on macOS
var sdk = try? self.systemSwiftSDK(
hostSDK.toolset.rootPaths.first,
environment: environment,
darwinPlatformOverride: darwinPlatform
)
sdk?.targetTriple = targetTriple
return sdk
}
#endif

return nil
}

Expand Down Expand Up @@ -688,12 +742,23 @@ public struct SwiftSDK: Equatable {
} else {
throw SwiftSDKError.noSwiftSDKDecoded(customDestination)
}
} else if let triple = customCompileTriple,
let targetSwiftSDK = SwiftSDK.defaultSwiftSDK(for: triple, hostSDK: hostSwiftSDK)
} else if let targetTriple = customCompileTriple,
let targetSwiftSDK = SwiftSDK.defaultSwiftSDK(for: targetTriple, hostSDK: hostSwiftSDK)
{
swiftSDK = targetSwiftSDK
} else if let swiftSDKSelector {
swiftSDK = try store.selectBundle(matching: swiftSDKSelector, hostTriple: hostTriple)
do {
swiftSDK = try store.selectBundle(matching: swiftSDKSelector, hostTriple: hostTriple)
} catch {
// If a user-installed bundle for the selector doesn't exist, check if the
// selector is recognized as a default SDK.
if let targetTriple = try? Triple(swiftSDKSelector),
let defaultSDK = SwiftSDK.defaultSwiftSDK(for: targetTriple, hostSDK: hostSwiftSDK) {
swiftSDK = defaultSDK
} else {
throw error
}
}
} else {
// Otherwise use the host toolchain.
swiftSDK = hostSwiftSDK
Expand Down Expand Up @@ -970,6 +1035,18 @@ extension SwiftSDK {
}
}

extension DarwinPlatform {
/// The name xcrun uses to identify this platform.
fileprivate var xcrunName: String {
switch self {
case .iOS(.catalyst):
return "macosx"
default:
return platformName
}
}
}

/// Integer version of the schema of `destination.json` files used for cross-compilation.
private struct VersionInfo: Codable {
let version: Int
Expand Down
13 changes: 13 additions & 0 deletions Tests/PackageModelTests/SwiftSDKBundleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,19 @@ final class SwiftSDKBundleTests: XCTestCase {
XCTAssertEqual(targetSwiftSDK.toolset.rootPaths, [toolsetRootPath] + hostSwiftSDK.toolset.rootPaths)
}

do {
let targetSwiftSDK = try SwiftSDK.deriveTargetSwiftSDK(
hostSwiftSDK: hostSwiftSDK,
hostTriple: hostTriple,
swiftSDKSelector: "wasm32-unknown-wasi",
store: store,
observabilityScope: system.topScope,
fileSystem: fileSystem
)
// Ensure that triples that have a `defaultSwiftSDK` are handled
XCTAssertEqual(targetSwiftSDK.targetTriple?.triple, "wasm32-unknown-wasi")
}

do {
// Check explicit overriding options.
let customCompileSDK = AbsolutePath("/path/to/sdk")
Expand Down
25 changes: 25 additions & 0 deletions Tests/PackageModelTests/SwiftSDKTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -616,4 +616,29 @@ final class DestinationTests: XCTestCase {
parsedDestinationV2GNU
)
}

func testDefaultSDKs() throws {
let hostSDK = try SwiftSDK.hostSwiftSDK("/prefix/bin")

#if os(macOS)
let iOSPlatform = try AbsolutePath(validating: "/usr/share/iPhoneOS.platform")
let iOSRoot = try AbsolutePath(validating: "/usr/share/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk")
let iOSTriple = try Triple("arm64-apple-ios")
let iOS = try XCTUnwrap(SwiftSDK.defaultSwiftSDK(
for: iOSTriple,
hostSDK: hostSDK,
environment: [
"SWIFTPM_PLATFORM_PATH_iphoneos": iOSPlatform.pathString,
"SWIFTPM_SDKROOT_iphoneos": iOSRoot.pathString,
]
))
XCTAssertEqual(iOS.toolset.rootPaths, hostSDK.toolset.rootPaths)

XCTAssertEqual(iOS.pathsConfiguration.sdkRootPath, iOSRoot)

let cFlags = iOS.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? []
XCTAssert(cFlags.contains(["-F", "\(iOSPlatform.pathString)/Developer/Library/Frameworks"]))
XCTAssertFalse(cFlags.contains { $0.lowercased().contains("macos") }, "Found macOS path in \(cFlags)")
#endif
}
}