@@ -524,6 +524,25 @@ public struct SwiftSDK: Equatable {
524524 environment: Environment = . current,
525525 observabilityScope: ObservabilityScope ? = nil ,
526526 fileSystem: any FileSystem = localFileSystem
527+ ) throws -> SwiftSDK {
528+ try self . systemSwiftSDK (
529+ binDir,
530+ environment: environment,
531+ observabilityScope: observabilityScope,
532+ fileSystem: fileSystem
533+ )
534+ }
535+
536+ /// A default Swift SDK on the host.
537+ ///
538+ /// Equivalent to `hostSwiftSDK`, except on macOS, where passing a non-nil `darwinPlatformOverride`
539+ /// will result in the SDK for the corresponding Darwin platform.
540+ private static func systemSwiftSDK(
541+ _ binDir: AbsolutePath ? = nil ,
542+ environment: Environment = . current,
543+ observabilityScope: ObservabilityScope ? = nil ,
544+ fileSystem: any FileSystem = localFileSystem,
545+ darwinPlatformOverride: DarwinPlatform ? = nil
527546 ) throws -> SwiftSDK {
528547 // Select the correct binDir.
529548 if environment [ " SWIFTPM_CUSTOM_BINDIR " ] != nil {
@@ -535,13 +554,16 @@ public struct SwiftSDK: Equatable {
535554
536555 let sdkPath : AbsolutePath ?
537556 #if os(macOS)
557+ let darwinPlatform = darwinPlatformOverride ?? . macOS
538558 // Get the SDK.
539559 if let value = environment [ " SDKROOT " ] {
540560 sdkPath = try AbsolutePath ( validating: value)
561+ } else if let value = environment [ EnvironmentKey ( " SWIFTPM_SDKROOT_ \( darwinPlatform. xcrunName) " ) ] {
562+ sdkPath = try AbsolutePath ( validating: value)
541563 } else {
542564 // No value in env, so search for it.
543565 let sdkPathStr = try AsyncProcess . checkNonZeroExit (
544- arguments: [ " /usr/bin/xcrun " , " --sdk " , " macosx " , " --show-sdk-path " ] ,
566+ arguments: [ " /usr/bin/xcrun " , " --sdk " , darwinPlatform . xcrunName , " --show-sdk-path " ] ,
545567 environment: environment
546568 ) . spm_chomp ( )
547569 guard !sdkPathStr. isEmpty else {
@@ -559,11 +581,11 @@ public struct SwiftSDK: Equatable {
559581 var extraSwiftCFlags : [ String ] = [ ]
560582 #if os(macOS)
561583 do {
562- let sdkPaths = try SwiftSDK . sdkPlatformFrameworkPaths ( environment: environment)
563- extraCCFlags += [ " -F " , sdkPaths. fwk . pathString]
564- extraSwiftCFlags += [ " -F " , sdkPaths. fwk . pathString]
565- extraSwiftCFlags += [ " -I " , sdkPaths. lib . pathString]
566- extraSwiftCFlags += [ " -L " , sdkPaths. lib . pathString]
584+ let sdkPaths = try SwiftSDK . sdkPlatformPaths ( for : darwinPlatform , environment: environment)
585+ extraCCFlags += [ " -F " , sdkPaths. frameworks . pathString]
586+ extraSwiftCFlags += [ " -F " , sdkPaths. frameworks . pathString]
587+ extraSwiftCFlags += [ " -I " , sdkPaths. libraries . pathString]
588+ extraSwiftCFlags += [ " -L " , sdkPaths. libraries . pathString]
567589 xctestSupport = . supported
568590 } catch {
569591 xctestSupport = . unsupported( reason: String ( describing: error) )
@@ -589,15 +611,40 @@ public struct SwiftSDK: Equatable {
589611 )
590612 }
591613
614+ /// Auxiliary platform frameworks and libraries.
615+ ///
616+ /// The referenced directories may contain, for example, test support utilities.
617+ ///
618+ /// - SeeAlso: ``sdkPlatformPaths(for:environment:)``
619+ public struct PlatformPaths {
620+ /// Path to the directory containing auxiliary platform frameworks.
621+ public var frameworks : AbsolutePath
622+
623+ /// Path to the directory containing auxiliary platform libraries.
624+ public var libraries : AbsolutePath
625+ }
626+
592627 /// Returns `macosx` sdk platform framework path.
628+ @available ( * , deprecated, message: " use sdkPlatformPaths(for:) instead " )
593629 public static func sdkPlatformFrameworkPaths(
594630 environment: Environment = . current
595631 ) throws -> ( fwk: AbsolutePath , lib: AbsolutePath ) {
596- if let path = _sdkPlatformFrameworkPath {
632+ let paths = try sdkPlatformPaths ( for: . macOS, environment: environment)
633+ return ( fwk: paths. frameworks, lib: paths. libraries)
634+ }
635+
636+ /// Returns ``SwiftSDK/PlatformPaths`` for the provided Darwin platform.
637+ public static func sdkPlatformPaths(
638+ for darwinPlatform: DarwinPlatform ,
639+ environment: Environment = . current
640+ ) throws -> PlatformPaths {
641+ if let path = _sdkPlatformFrameworkPath [ darwinPlatform] {
597642 return path
598643 }
599- let platformPath = try AsyncProcess . checkNonZeroExit (
600- arguments: [ " /usr/bin/xcrun " , " --sdk " , " macosx " , " --show-sdk-platform-path " ] ,
644+ let platformPath = try environment [
645+ EnvironmentKey ( " SWIFTPM_PLATFORM_PATH_ \( darwinPlatform. xcrunName) " )
646+ ] ?? AsyncProcess . checkNonZeroExit (
647+ arguments: [ " /usr/bin/xcrun " , " --sdk " , darwinPlatform. xcrunName, " --show-sdk-platform-path " ] ,
601648 environment: environment
602649 ) . spm_chomp ( )
603650
@@ -615,33 +662,26 @@ public struct SwiftSDK: Equatable {
615662 components: " Developer " , " usr " , " lib "
616663 )
617664
618- let sdkPlatformFrameworkPath = ( fwk, lib)
619- _sdkPlatformFrameworkPath = sdkPlatformFrameworkPath
665+ let sdkPlatformFrameworkPath = PlatformPaths ( frameworks : fwk, libraries : lib)
666+ _sdkPlatformFrameworkPath [ darwinPlatform ] = sdkPlatformFrameworkPath
620667 return sdkPlatformFrameworkPath
621668 }
622669
623- // FIXME: convert this from a tuple to a proper struct with documented properties
624- /// Cache storage for sdk platform path.
625- private static var _sdkPlatformFrameworkPath : ( fwk: AbsolutePath , lib: AbsolutePath ) ? = nil
670+ /// Cache storage for sdk platform paths.
671+ private static var _sdkPlatformFrameworkPath : [ DarwinPlatform : PlatformPaths ] = [ : ]
626672
627673 /// Returns a default Swift SDK for a given target environment
628674 @available ( * , deprecated, renamed: " defaultSwiftSDK " )
629675 public static func defaultDestination( for triple: Triple , host: SwiftSDK ) -> SwiftSDK ? {
630- if triple. isWASI ( ) {
631- let wasiSysroot = host. toolset. rootPaths. first?
632- . parentDirectory // usr
633- . appending ( components: " share " , " wasi-sysroot " )
634- return SwiftSDK (
635- targetTriple: triple,
636- toolset: host. toolset,
637- pathsConfiguration: . init( sdkRootPath: wasiSysroot)
638- )
639- }
640- return nil
676+ defaultSwiftSDK ( for: triple, hostSDK: host)
641677 }
642678
643679 /// Returns a default Swift SDK of a given target environment.
644- public static func defaultSwiftSDK( for targetTriple: Triple , hostSDK: SwiftSDK ) -> SwiftSDK ? {
680+ public static func defaultSwiftSDK(
681+ for targetTriple: Triple ,
682+ hostSDK: SwiftSDK ,
683+ environment: Environment = . current
684+ ) -> SwiftSDK ? {
645685 if targetTriple. isWASI ( ) {
646686 let wasiSysroot = hostSDK. toolset. rootPaths. first?
647687 . parentDirectory // usr
@@ -652,6 +692,20 @@ public struct SwiftSDK: Equatable {
652692 pathsConfiguration: . init( sdkRootPath: wasiSysroot)
653693 )
654694 }
695+
696+ #if os(macOS)
697+ if let darwinPlatform = targetTriple. darwinPlatform {
698+ // the Darwin SDKs are trivially available on macOS
699+ var sdk = try ? self . systemSwiftSDK (
700+ hostSDK. toolset. rootPaths. first,
701+ environment: environment,
702+ darwinPlatformOverride: darwinPlatform
703+ )
704+ sdk? . targetTriple = targetTriple
705+ return sdk
706+ }
707+ #endif
708+
655709 return nil
656710 }
657711
@@ -690,12 +744,23 @@ public struct SwiftSDK: Equatable {
690744 } else {
691745 throw SwiftSDKError . noSwiftSDKDecoded ( customDestination)
692746 }
693- } else if let triple = customCompileTriple,
694- let targetSwiftSDK = SwiftSDK . defaultSwiftSDK ( for: triple , hostSDK: hostSwiftSDK)
747+ } else if let targetTriple = customCompileTriple,
748+ let targetSwiftSDK = SwiftSDK . defaultSwiftSDK ( for: targetTriple , hostSDK: hostSwiftSDK)
695749 {
696750 swiftSDK = targetSwiftSDK
697751 } else if let swiftSDKSelector {
698- swiftSDK = try store. selectBundle ( matching: swiftSDKSelector, hostTriple: hostTriple)
752+ do {
753+ swiftSDK = try store. selectBundle ( matching: swiftSDKSelector, hostTriple: hostTriple)
754+ } catch {
755+ // If a user-installed bundle for the selector doesn't exist, check if the
756+ // selector is recognized as a default SDK.
757+ if let targetTriple = try ? Triple ( swiftSDKSelector) ,
758+ let defaultSDK = SwiftSDK . defaultSwiftSDK ( for: targetTriple, hostSDK: hostSwiftSDK) {
759+ swiftSDK = defaultSDK
760+ } else {
761+ throw error
762+ }
763+ }
699764 } else {
700765 // Otherwise use the host toolchain.
701766 swiftSDK = hostSwiftSDK
@@ -991,6 +1056,18 @@ extension SwiftSDK {
9911056 }
9921057}
9931058
1059+ extension DarwinPlatform {
1060+ /// The name xcrun uses to identify this platform.
1061+ fileprivate var xcrunName : String {
1062+ switch self {
1063+ case . iOS( . catalyst) :
1064+ return " macosx "
1065+ default :
1066+ return platformName
1067+ }
1068+ }
1069+ }
1070+
9941071/// Integer version of the schema of `destination.json` files used for cross-compilation.
9951072private struct VersionInfo : Codable {
9961073 let version : Int
0 commit comments