Skip to content

Commit 8bac989

Browse files
committed
Add back async versions until the ecosystem can adopt the async versions
1 parent 01419ce commit 8bac989

File tree

2 files changed

+341
-0
lines changed

2 files changed

+341
-0
lines changed

Sources/PackageModel/SwiftSDKs/SwiftSDK.swift

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,22 @@ public struct SwiftSDK: Equatable {
529529
try await self.hostSwiftSDK(binDir, environment: environment)
530530
}
531531

532+
/// The Swift SDK for the host platform.
533+
@available(*, deprecated, message: "Use the async alternative")
534+
public static func hostSwiftSDK(
535+
_ binDir: Basics.AbsolutePath? = nil,
536+
environment: Environment = .current,
537+
observabilityScope: ObservabilityScope? = nil,
538+
fileSystem: any FileSystem = Basics.localFileSystem
539+
) throws -> SwiftSDK {
540+
try self.systemSwiftSDK(
541+
binDir,
542+
environment: environment,
543+
observabilityScope: observabilityScope,
544+
fileSystem: fileSystem
545+
)
546+
}
547+
532548
/// The Swift SDK for the host platform.
533549
public static func hostSwiftSDK(
534550
_ binDir: Basics.AbsolutePath? = nil,
@@ -544,6 +560,37 @@ public struct SwiftSDK: Equatable {
544560
)
545561
}
546562

563+
/// A default Swift SDK on the host.
564+
///
565+
/// Equivalent to `hostSwiftSDK`, except on macOS, where passing a non-nil `darwinPlatformOverride`
566+
/// will result in the SDK for the corresponding Darwin platform.
567+
private static func systemSwiftSDK(
568+
_ binDir: Basics.AbsolutePath? = nil,
569+
environment: Environment = .current,
570+
observabilityScope: ObservabilityScope? = nil,
571+
fileSystem: any FileSystem = Basics.localFileSystem,
572+
darwinPlatformOverride: DarwinPlatform? = nil
573+
) throws -> SwiftSDK {
574+
#if os(macOS)
575+
let darwinPlatform = darwinPlatformOverride ?? .macOS
576+
let sdkPath = try Self.getSDKPath(
577+
for: darwinPlatform,
578+
environment: environment
579+
)
580+
let sdkPaths = try? SwiftSDK.sdkPlatformPaths(for: darwinPlatform, environment: environment)
581+
#else
582+
let sdkPath: Basics.AbsolutePath? = nil
583+
let sdkPaths: PlatformPaths? = nil
584+
#endif
585+
586+
return try Self.buildSwiftSDK(
587+
binDir: binDir,
588+
sdkPath: sdkPath,
589+
sdkPaths: sdkPaths,
590+
environment: environment,
591+
fileSystem: fileSystem
592+
)
593+
}
547594

548595
/// A default Swift SDK on the host.
549596
///
@@ -577,6 +624,27 @@ public struct SwiftSDK: Equatable {
577624
)
578625
}
579626

627+
/// Helper to get the SDK path for a Darwin platform (async version).
628+
private static func getSDKPath(
629+
for darwinPlatform: DarwinPlatform,
630+
environment: Environment
631+
) throws -> Basics.AbsolutePath {
632+
if let value = environment["SDKROOT"] {
633+
return try AbsolutePath(validating: value)
634+
} else if let value = environment[EnvironmentKey("SWIFTPM_SDKROOT_\(darwinPlatform.xcrunName)")] {
635+
return try AbsolutePath(validating: value)
636+
} else {
637+
let sdkPathStr = try AsyncProcess.checkNonZeroExit(
638+
arguments: ["/usr/bin/xcrun", "--sdk", darwinPlatform.xcrunName, "--show-sdk-path"],
639+
environment: environment
640+
).spm_chomp()
641+
guard !sdkPathStr.isEmpty else {
642+
throw SwiftSDKError.invalidInstallation("default SDK not found")
643+
}
644+
return try AbsolutePath(validating: sdkPathStr)
645+
}
646+
}
647+
580648
/// Helper to get the SDK path for a Darwin platform (async version).
581649
private static func getSDKPath(
582650
for darwinPlatform: DarwinPlatform,
@@ -674,6 +742,46 @@ public struct SwiftSDK: Equatable {
674742
return (fwk: frameworkPath, lib: libraryPath)
675743
}
676744

745+
/// Returns ``SwiftSDK/PlatformPaths`` for the provided Darwin platform.
746+
public static func sdkPlatformPaths(
747+
for darwinPlatform: DarwinPlatform,
748+
environment: Environment = .current
749+
) throws -> PlatformPaths {
750+
if let path = _sdkPlatformFrameworkPath[darwinPlatform] {
751+
return path
752+
}
753+
let platformPath: String
754+
if let envValue = environment[EnvironmentKey("SWIFTPM_PLATFORM_PATH_\(darwinPlatform.xcrunName)")] {
755+
platformPath = envValue
756+
} else {
757+
platformPath = try AsyncProcess.checkNonZeroExit(
758+
arguments: ["/usr/bin/xcrun", "--sdk", darwinPlatform.xcrunName, "--show-sdk-platform-path"],
759+
environment: environment
760+
).spm_chomp()
761+
}
762+
763+
guard !platformPath.isEmpty else {
764+
throw StringError("could not determine SDK platform path")
765+
}
766+
767+
// For testing frameworks.
768+
let frameworksPath = try Basics.AbsolutePath(validating: platformPath).appending(
769+
components: "Developer", "Library", "Frameworks"
770+
)
771+
let privateFrameworksPath = try Basics.AbsolutePath(validating: platformPath).appending(
772+
components: "Developer", "Library", "PrivateFrameworks"
773+
)
774+
775+
// For testing libraries.
776+
let librariesPath = try Basics.AbsolutePath(validating: platformPath).appending(
777+
components: "Developer", "usr", "lib"
778+
)
779+
780+
let sdkPlatformFrameworkPath = PlatformPaths(frameworks: [frameworksPath, privateFrameworksPath], libraries: [librariesPath])
781+
_sdkPlatformFrameworkPath[darwinPlatform] = sdkPlatformFrameworkPath
782+
return sdkPlatformFrameworkPath
783+
}
784+
677785
/// Returns ``SwiftSDK/PlatformPaths`` for the provided Darwin platform.
678786
public static func sdkPlatformPaths(
679787
for darwinPlatform: DarwinPlatform,

Sources/PackageModel/UserToolchain.swift

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,27 @@ public final class UserToolchain: Toolchain {
175175
return try getTool(name, binDirectories: envSearchPaths, fileSystem: fileSystem)
176176
}
177177

178+
private static func getTargetInfo(swiftCompiler: AbsolutePath) throws -> JSON {
179+
// Call the compiler to get the target info JSON.
180+
let compilerOutput: String
181+
do {
182+
let result = try AsyncProcess.popen(args: swiftCompiler.pathString, "-print-target-info")
183+
compilerOutput = try result.utf8Output().spm_chomp()
184+
} catch {
185+
throw InternalError(
186+
"Failed to load target info (\(error.interpolationDescription))"
187+
)
188+
}
189+
// Parse the compiler's JSON output.
190+
do {
191+
return try JSON(string: compilerOutput)
192+
} catch {
193+
throw InternalError(
194+
"Failed to parse target info (\(error.interpolationDescription)).\nRaw compiler output: \(compilerOutput)"
195+
)
196+
}
197+
}
198+
178199
private static func getTargetInfo(swiftCompiler: AbsolutePath) async throws -> JSON {
179200
// Call the compiler to get the target info JSON.
180201
let compilerOutput: String
@@ -666,6 +687,218 @@ public final class UserToolchain: Toolchain {
666687
case custom(searchPaths: [AbsolutePath], useXcrun: Bool = true)
667688
}
668689

690+
@available(*, deprecated, message: "Use the async alternative")
691+
public init(
692+
swiftSDK: SwiftSDK,
693+
environment: Environment = .current,
694+
searchStrategy: SearchStrategy = .default,
695+
customTargetInfo: JSON? = nil,
696+
customLibrariesLocation: ToolchainConfiguration.SwiftPMLibrariesLocation? = nil,
697+
customInstalledSwiftPMConfiguration: InstalledSwiftPMConfiguration? = nil,
698+
fileSystem: any FileSystem = localFileSystem
699+
) throws {
700+
self.swiftSDK = swiftSDK
701+
self.environment = environment
702+
703+
switch searchStrategy {
704+
case .default:
705+
// Get the search paths from PATH.
706+
self.envSearchPaths = getEnvSearchPaths(
707+
pathString: environment[.path],
708+
currentWorkingDirectory: fileSystem.currentWorkingDirectory
709+
)
710+
self.useXcrun = !(fileSystem is InMemoryFileSystem)
711+
case .custom(let searchPaths, let useXcrun):
712+
self.envSearchPaths = searchPaths
713+
self.useXcrun = useXcrun
714+
}
715+
716+
let swiftCompilers = try UserToolchain.determineSwiftCompilers(
717+
binDirectories: swiftSDK.toolset.rootPaths,
718+
useXcrun: self.useXcrun,
719+
environment: environment,
720+
searchPaths: self.envSearchPaths,
721+
fileSystem: fileSystem
722+
)
723+
self.swiftCompilerPath = swiftCompilers.compile
724+
self.architectures = swiftSDK.architectures
725+
726+
if let customInstalledSwiftPMConfiguration {
727+
self.installedSwiftPMConfiguration = customInstalledSwiftPMConfiguration
728+
} else {
729+
let path = swiftCompilerPath.parentDirectory.parentDirectory.appending(components: [
730+
"share", "pm", "config.json",
731+
])
732+
self.installedSwiftPMConfiguration = try Self.loadJSONResource(
733+
config: path,
734+
type: InstalledSwiftPMConfiguration.self,
735+
default: InstalledSwiftPMConfiguration.default)
736+
}
737+
738+
var triple: Basics.Triple
739+
if let targetTriple = swiftSDK.targetTriple {
740+
self.targetInfo = nil
741+
triple = targetTriple
742+
} else {
743+
// targetInfo from the compiler
744+
let targetInfo: JSON
745+
if let customTargetInfo {
746+
targetInfo = customTargetInfo
747+
} else {
748+
targetInfo = try Self.getTargetInfo(swiftCompiler: swiftCompilers.compile)
749+
}
750+
self.targetInfo = targetInfo
751+
triple = try swiftSDK.targetTriple ?? Self.getHostTriple(targetInfo: targetInfo, versioned: false)
752+
}
753+
754+
// Change the triple to the specified arch if there's exactly one of them.
755+
// The Triple property is only looked at by the native build system currently.
756+
if let architectures = self.architectures, architectures.count == 1 {
757+
let components = triple.tripleString.drop(while: { $0 != "-" })
758+
triple = try Triple(architectures[0] + components)
759+
}
760+
761+
self.targetTriple = triple
762+
763+
var swiftCompilerFlags: [String] = []
764+
var extraLinkerFlags: [String] = []
765+
766+
let swiftTestingPath: AbsolutePath? = try Self.deriveSwiftTestingPath(
767+
derivedSwiftCompiler: swiftCompilers.compile,
768+
swiftSDK: self.swiftSDK,
769+
triple: triple,
770+
environment: environment,
771+
fileSystem: fileSystem
772+
)
773+
774+
if triple.isMacOSX, let swiftTestingPath {
775+
// Swift Testing is a framework (e.g. from CommandLineTools) so use -F.
776+
if swiftTestingPath.extension == "framework" {
777+
swiftCompilerFlags += ["-F", swiftTestingPath.pathString]
778+
779+
// Otherwise Swift Testing is assumed to be a swiftmodule + library, so use -I and -L.
780+
} else {
781+
swiftCompilerFlags += [
782+
"-I", swiftTestingPath.pathString,
783+
"-L", swiftTestingPath.pathString,
784+
]
785+
}
786+
}
787+
788+
// Specify the plugin path for Swift Testing's macro plugin if such a
789+
// path exists in this toolchain.
790+
if let swiftTestingPluginPath = Self.deriveSwiftTestingPluginPath(
791+
derivedSwiftCompiler: swiftCompilers.compile,
792+
fileSystem: fileSystem
793+
) {
794+
swiftCompilerFlags += ["-plugin-path", swiftTestingPluginPath.pathString]
795+
}
796+
797+
swiftCompilerFlags += try Self.deriveSwiftCFlags(
798+
triple: triple,
799+
swiftSDK: swiftSDK,
800+
environment: environment,
801+
fileSystem: fileSystem
802+
)
803+
804+
extraLinkerFlags += swiftSDK.toolset.knownTools[.linker]?.extraCLIOptions ?? []
805+
806+
self.extraFlags = BuildFlags(
807+
cCompilerFlags: swiftSDK.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [],
808+
cxxCompilerFlags: swiftSDK.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? [],
809+
swiftCompilerFlags: swiftCompilerFlags,
810+
linkerFlags: extraLinkerFlags,
811+
xcbuildFlags: swiftSDK.toolset.knownTools[.xcbuild]?.extraCLIOptions ?? [])
812+
813+
self.includeSearchPaths = swiftSDK.pathsConfiguration.includeSearchPaths ?? []
814+
self.librarySearchPaths = swiftSDK.pathsConfiguration.includeSearchPaths ?? []
815+
816+
self.librarianPath = try swiftSDK.toolset.knownTools[.librarian]?.path ?? UserToolchain.determineLibrarian(
817+
triple: triple,
818+
binDirectories: swiftSDK.toolset.rootPaths,
819+
useXcrun: useXcrun,
820+
environment: environment,
821+
searchPaths: envSearchPaths,
822+
extraSwiftFlags: self.extraFlags.swiftCompilerFlags,
823+
fileSystem: fileSystem
824+
)
825+
826+
if let sdkDir = swiftSDK.pathsConfiguration.sdkRootPath {
827+
let sysrootFlags = [triple.isDarwin() ? "-isysroot" : "--sysroot", sdkDir.pathString]
828+
self.extraFlags.cCompilerFlags.insert(contentsOf: sysrootFlags, at: 0)
829+
}
830+
831+
if triple.isWindows() {
832+
if let root = environment.windowsSDKRoot {
833+
if let settings = WindowsSDKSettings(
834+
reading: root.appending("SDKSettings.plist"),
835+
observabilityScope: nil,
836+
filesystem: fileSystem
837+
) {
838+
switch settings.defaults.runtime {
839+
case .multithreadedDebugDLL:
840+
// Defines _DEBUG, _MT, and _DLL
841+
// Linker uses MSVCRTD.lib
842+
self.extraFlags.cCompilerFlags += [
843+
"-D_DEBUG",
844+
"-D_MT",
845+
"-D_DLL",
846+
"-Xclang",
847+
"--dependent-lib=msvcrtd",
848+
]
849+
850+
case .multithreadedDLL:
851+
// Defines _MT, and _DLL
852+
// Linker uses MSVCRT.lib
853+
self.extraFlags.cCompilerFlags += ["-D_MT", "-D_DLL", "-Xclang", "--dependent-lib=msvcrt"]
854+
855+
case .multithreadedDebug:
856+
// Defines _DEBUG, and _MT
857+
// Linker uses LIBCMTD.lib
858+
self.extraFlags.cCompilerFlags += ["-D_DEBUG", "-D_MT", "-Xclang", "--dependent-lib=libcmtd"]
859+
860+
case .multithreaded:
861+
// Defines _MT
862+
// Linker uses LIBCMT.lib
863+
self.extraFlags.cCompilerFlags += ["-D_MT", "-Xclang", "--dependent-lib=libcmt"]
864+
}
865+
}
866+
}
867+
}
868+
869+
let swiftPMLibrariesLocation = try customLibrariesLocation ?? Self.deriveSwiftPMLibrariesLocation(
870+
swiftCompilerPath: swiftCompilerPath,
871+
swiftSDK: swiftSDK,
872+
environment: environment,
873+
fileSystem: fileSystem
874+
)
875+
876+
let xctestPath: AbsolutePath?
877+
if case .custom(_, let useXcrun) = searchStrategy, !useXcrun {
878+
xctestPath = nil
879+
} else {
880+
xctestPath = try Self.deriveXCTestPath(
881+
swiftSDK: self.swiftSDK,
882+
triple: triple,
883+
environment: environment,
884+
fileSystem: fileSystem
885+
)
886+
}
887+
888+
self.configuration = .init(
889+
librarianPath: librarianPath,
890+
swiftCompilerPath: swiftCompilers.manifest,
891+
swiftCompilerFlags: self.extraFlags.swiftCompilerFlags,
892+
swiftCompilerEnvironment: environment,
893+
swiftPMLibrariesLocation: swiftPMLibrariesLocation,
894+
sdkRootPath: self.swiftSDK.pathsConfiguration.sdkRootPath,
895+
xctestPath: xctestPath,
896+
swiftTestingPath: swiftTestingPath
897+
)
898+
899+
self.fileSystem = fileSystem
900+
}
901+
669902
public init(
670903
swiftSDK: SwiftSDK,
671904
environment: Environment = .current,

0 commit comments

Comments
 (0)