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 5 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
75 changes: 56 additions & 19 deletions Sources/PackageModel/SwiftSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,23 @@ public struct SwiftSDK: Equatable {
_ binDir: AbsolutePath? = nil,
originalWorkingDirectory: AbsolutePath? = nil,
environment: [String: String] = ProcessEnv.vars
) throws -> SwiftSDK {
try self.systemSwiftSDK(
binDir,
originalWorkingDirectory: originalWorkingDirectory,
environment: environment
)
}

/// 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,
originalWorkingDirectory: AbsolutePath? = nil,
environment: [String: String] = ProcessEnv.vars,
darwinPlatformOverride: DarwinPlatform? = nil
) throws -> SwiftSDK {
let originalWorkingDirectory = originalWorkingDirectory ?? localFileSystem.currentWorkingDirectory
// Select the correct binDir.
Expand All @@ -464,13 +481,14 @@ public struct SwiftSDK: Equatable {

let sdkPath: AbsolutePath?
#if os(macOS)
let darwinPlatform = darwinPlatformOverride ?? .macOS
// Get the SDK.
if let value = lookupExecutablePath(filename: ProcessEnv.vars["SDKROOT"]) {
sdkPath = value
} else {
// No value in env, so search for it.
let sdkPathStr = try TSCBasic.Process.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 @@ -486,7 +504,7 @@ public struct SwiftSDK: Equatable {
var extraCCFlags: [String] = []
var extraSwiftCFlags: [String] = []
#if os(macOS)
let sdkPaths = try SwiftSDK.sdkPlatformFrameworkPaths(environment: environment)
let sdkPaths = try SwiftSDK.sdkPlatformFrameworkPaths(for: darwinPlatform, environment: environment)
extraCCFlags += ["-F", sdkPaths.fwk.pathString]
extraSwiftCFlags += ["-F", sdkPaths.fwk.pathString]
extraSwiftCFlags += ["-I", sdkPaths.lib.pathString]
Expand All @@ -509,15 +527,16 @@ public struct SwiftSDK: Equatable {
)
}

/// Returns `macosx` sdk platform framework path.
/// Returns framework paths for the provided Darwin platform.
public static func sdkPlatformFrameworkPaths(
for darwinPlatform: DarwinPlatform = .macOS,
environment: EnvironmentVariables = .process()
) throws -> (fwk: AbsolutePath, lib: AbsolutePath) {
if let path = _sdkPlatformFrameworkPath {
if let path = _sdkPlatformFrameworkPath[darwinPlatform] {
return path
}
let platformPath = try TSCBasic.Process.checkNonZeroExit(
arguments: ["/usr/bin/xcrun", "--sdk", "macosx", "--show-sdk-platform-path"],
arguments: ["/usr/bin/xcrun", "--sdk", darwinPlatform.platformName, "--show-sdk-platform-path"],
environment: environment
).spm_chomp()

Expand All @@ -536,32 +555,26 @@ public struct SwiftSDK: Equatable {
)

let sdkPlatformFrameworkPath = (fwk, lib)
_sdkPlatformFrameworkPath = sdkPlatformFrameworkPath
_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
private static var _sdkPlatformFrameworkPath: [DarwinPlatform: (fwk: AbsolutePath, lib: AbsolutePath)] = [:]

/// Returns a default destination of 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: [String: String] = ProcessEnv.vars
) -> SwiftSDK? {
if targetTriple.isWASI() {
let wasiSysroot = hostSDK.toolset.rootPaths.first?
.parentDirectory // usr
Expand All @@ -572,6 +585,18 @@ public struct SwiftSDK: Equatable {
pathsConfiguration: .init(sdkRootPath: wasiSysroot)
)
}

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

return nil
}

Expand Down Expand Up @@ -796,6 +821,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
19 changes: 19 additions & 0 deletions Tests/PackageModelTests/SwiftSDKTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -554,4 +554,23 @@ final class DestinationTests: XCTestCase {
parsedDestinationV2Musl
)
}

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

#if os(macOS)
let iOSTriple = try Triple("arm64-apple-ios")
let iOS = try XCTUnwrap(SwiftSDK.defaultSwiftSDK(for: iOSTriple, hostSDK: hostSDK))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the SwiftPM test suite have a way to mock shell invocations? This invokes xcrun so it would be great to 1) verify that xcrun is indeed invoked and 2) mock the result.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no such mocking available at the moment, unfortunately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and of course this is precisely the test that fails on CI 😶 Looks like it can't find iPhoneOS.sdk — could that be because the iOS component isn't installed in the runner's Xcode?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's quite likely, since we're not building for iOS on Swift CI. IMO better not to rely on that to be present.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaxDesiatov do you know if this is still the case? Worth triggering CI again to confirm? If so I could add some plumbing to inject xcrun as a mockable dependency instead.

XCTAssertEqual(iOS.toolset.rootPaths, hostSDK.toolset.rootPaths)

let sdkPath = try XCTUnwrap(iOS.pathsConfiguration.sdkRootPath)
XCTAssertEqual(sdkPath.extension, "sdk")

let sdkName = try XCTUnwrap(sdkPath.components.last)
XCTAssert(sdkName.hasPrefix("iPhoneOS"))

let cFlags = iOS.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? []
XCTAssertFalse(cFlags.contains { $0.lowercased().contains("macos") }, "Found macOS path in \(cFlags)")
#endif
}
}