@@ -15,11 +15,44 @@ import SWBCore
1515import Foundation
1616
1717@PluginExtensionSystemActor public func initializePlugin(_ manager: PluginManager) {
18+ let plugin = GenericUnixPlugin()
1819 manager.register(GenericUnixDeveloperDirectoryExtension(), type: DeveloperDirectoryExtensionPoint.self)
1920 manager.register(GenericUnixPlatformSpecsExtension(), type: SpecificationsExtensionPoint.self)
2021 manager.register(GenericUnixPlatformInfoExtension(), type: PlatformInfoExtensionPoint.self)
21- manager.register(GenericUnixSDKRegistryExtension(), type: SDKRegistryExtensionPoint.self)
22- manager.register(GenericUnixToolchainRegistryExtension(), type: ToolchainRegistryExtensionPoint.self)
22+ manager.register(GenericUnixSDKRegistryExtension(plugin: plugin), type: SDKRegistryExtensionPoint.self)
23+ manager.register(GenericUnixToolchainRegistryExtension(plugin: plugin), type: ToolchainRegistryExtensionPoint.self)
24+ }
25+
26+ final class GenericUnixPlugin: Sendable {
27+ func swiftExecutablePath(fs: any FSProxy) -> Path? {
28+ [
29+ Environment.current["SWIFT_EXEC"].map(Path.init),
30+ StackedSearchPath(environment: .current, fs: fs).lookup(Path("swift"))
31+ ].compactMap { $0 }.first(where: fs.exists)
32+ }
33+
34+ func swiftTargetInfo(swiftExecutablePath: Path) async throws -> SwiftTargetInfo {
35+ let args = ["-print-target-info"]
36+ let executionResult = try await Process.getOutput(url: URL(fileURLWithPath: swiftExecutablePath.str), arguments: args)
37+ guard executionResult.exitStatus.isSuccess else {
38+ throw RunProcessNonZeroExitError(args: [swiftExecutablePath.str] + args, workingDirectory: nil, environment: [:], status: executionResult.exitStatus, stdout: ByteString(executionResult.stdout), stderr: ByteString(executionResult.stderr))
39+ }
40+ return try JSONDecoder().decode(SwiftTargetInfo.self, from: executionResult.stdout)
41+ }
42+ }
43+
44+ struct SwiftTargetInfo: Decodable {
45+ struct TargetInfo: Decodable {
46+ let triple: LLVMTriple
47+ let unversionedTriple: LLVMTriple
48+ }
49+ let target: TargetInfo
50+ }
51+
52+ extension SwiftTargetInfo.TargetInfo {
53+ var tripleVersion: String? {
54+ triple != unversionedTriple && triple.system.hasPrefix(unversionedTriple.system) ? String(triple.system.dropFirst(unversionedTriple.system.count)).nilIfEmpty : nil
55+ }
2356}
2457
2558struct GenericUnixDeveloperDirectoryExtension: DeveloperDirectoryExtension {
@@ -69,9 +102,11 @@ struct GenericUnixPlatformInfoExtension: PlatformInfoExtension {
69102}
70103
71104struct GenericUnixSDKRegistryExtension: SDKRegistryExtension {
105+ let plugin: GenericUnixPlugin
106+
72107 func additionalSDKs(context: any SDKRegistryExtensionAdditionalSDKsContext) async throws -> [(path: Path, platform: SWBCore.Platform?, data: [String: PropertyListItem])] {
73108 let operatingSystem = context.hostOperatingSystem
74- guard operatingSystem.createFallbackSystemToolchain, let platform = try context.platformRegistry.lookup(name: operatingSystem.xcodePlatformName) else {
109+ guard operatingSystem.createFallbackSystemToolchain, let platform = try context.platformRegistry.lookup(name: operatingSystem.xcodePlatformName), let swift = plugin.swiftExecutablePath(fs: context.fs) else {
75110 return []
76111 }
77112
@@ -100,6 +135,23 @@ struct GenericUnixSDKRegistryExtension: SDKRegistryExtension {
100135 tripleEnvironment = ""
101136 }
102137
138+ let swiftTargetInfo = try await plugin.swiftTargetInfo(swiftExecutablePath: swift)
139+
140+ let deploymentTargetSettings: [String: PropertyListItem]
141+ if operatingSystem == .freebsd {
142+ guard let tripleVersion = swiftTargetInfo.target.tripleVersion else {
143+ throw StubError.error("Unknown FreeBSD triple version")
144+ }
145+ deploymentTargetSettings = [
146+ "DeploymentTargetSettingName": .plString("FREEBSD_DEPLOYMENT_TARGET"),
147+ "DefaultDeploymentTarget": .plString(tripleVersion),
148+ "MinimumDeploymentTarget": .plString(tripleVersion),
149+ "MaximumDeploymentTarget": .plString(tripleVersion),
150+ ]
151+ } else {
152+ deploymentTargetSettings = [:]
153+ }
154+
103155 return try [(.root, platform, [
104156 "Type": .plString("SDK"),
105157 "Version": .plString(Version(ProcessInfo.processInfo.operatingSystemVersion).zeroTrimmed.description),
@@ -114,62 +166,54 @@ struct GenericUnixSDKRegistryExtension: SDKRegistryExtension {
114166 "LLVMTargetTripleEnvironment": .plString(tripleEnvironment),
115167 "LLVMTargetTripleSys": .plString(operatingSystem.xcodePlatformName),
116168 "LLVMTargetTripleVendor": .plString("unknown"),
117- ])
169+ ].merging(deploymentTargetSettings, uniquingKeysWith: { _, new in new }) )
118170 ]),
119171 ])]
120172 }
121173}
122174
123175struct GenericUnixToolchainRegistryExtension: ToolchainRegistryExtension {
176+ let plugin: GenericUnixPlugin
177+
124178 func additionalToolchains(context: any ToolchainRegistryExtensionAdditionalToolchainsContext) async throws -> [Toolchain] {
125179 let operatingSystem = context.hostOperatingSystem
126- guard operatingSystem.createFallbackSystemToolchain else {
180+ let fs = context.fs
181+ guard operatingSystem.createFallbackSystemToolchain, let swift = plugin.swiftExecutablePath(fs: fs) else {
127182 return []
128183 }
129184
130- let fs = context.fs
131-
132- for swift in [
133- Environment.current["SWIFT_EXEC"].map(Path.init),
134- StackedSearchPath(environment: .current, fs: fs).lookup(Path("swift"))
135- ].compactMap(\.self) {
136- if fs.exists(swift) {
137- let realSwiftPath = try fs.realpath(swift).dirname.normalize()
138- let hasUsrBin = realSwiftPath.str.hasSuffix("/usr/bin")
139- let hasUsrLocalBin = realSwiftPath.str.hasSuffix("/usr/local/bin")
140- let path: Path
141- switch (hasUsrBin, hasUsrLocalBin) {
142- case (true, false):
143- path = realSwiftPath.dirname.dirname
144- case (false, true):
145- path = realSwiftPath.dirname.dirname.dirname
146- case (false, false):
147- throw StubError.error("Unexpected toolchain layout for Swift installation path: \(realSwiftPath)")
148- case (true, true):
149- preconditionFailure()
150- }
151- let llvmDirectories = try Array(fs.listdir(Path("/usr/lib")).filter { $0.hasPrefix("llvm-") }.sorted().reversed())
152- let llvmDirectoriesLocal = try Array(fs.listdir(Path("/usr/local")).filter { $0.hasPrefix("llvm") }.sorted().reversed())
153- return [
154- Toolchain(
155- identifier: ToolchainRegistry.defaultToolchainIdentifier,
156- displayName: "Default",
157- version: Version(),
158- aliases: ["default"],
159- path: path,
160- frameworkPaths: [],
161- libraryPaths: llvmDirectories.map { "/usr/lib/\($0)/lib" } + llvmDirectoriesLocal.map { "/usr/local/\($0)/lib" } + ["/usr/lib64"],
162- defaultSettings: [:],
163- overrideSettings: [:],
164- defaultSettingsWhenPrimary: [:],
165- executableSearchPaths: realSwiftPath.dirname.relativeSubpath(from: path).map { [path.join($0).join("bin")] } ?? [],
166- testingLibraryPlatformNames: [],
167- fs: fs)
168- ]
169- }
185+ let realSwiftPath = try fs.realpath(swift).dirname.normalize()
186+ let hasUsrBin = realSwiftPath.str.hasSuffix("/usr/bin")
187+ let hasUsrLocalBin = realSwiftPath.str.hasSuffix("/usr/local/bin")
188+ let path: Path
189+ switch (hasUsrBin, hasUsrLocalBin) {
190+ case (true, false):
191+ path = realSwiftPath.dirname.dirname
192+ case (false, true):
193+ path = realSwiftPath.dirname.dirname.dirname
194+ case (false, false):
195+ throw StubError.error("Unexpected toolchain layout for Swift installation path: \(realSwiftPath)")
196+ case (true, true):
197+ preconditionFailure()
170198 }
171-
172- return []
199+ let llvmDirectories = try Array(fs.listdir(Path("/usr/lib")).filter { $0.hasPrefix("llvm-") }.sorted().reversed())
200+ let llvmDirectoriesLocal = try Array(fs.listdir(Path("/usr/local")).filter { $0.hasPrefix("llvm") }.sorted().reversed())
201+ return [
202+ Toolchain(
203+ identifier: ToolchainRegistry.defaultToolchainIdentifier,
204+ displayName: "Default",
205+ version: Version(),
206+ aliases: ["default"],
207+ path: path,
208+ frameworkPaths: [],
209+ libraryPaths: llvmDirectories.map { "/usr/lib/\($0)/lib" } + llvmDirectoriesLocal.map { "/usr/local/\($0)/lib" } + ["/usr/lib64"],
210+ defaultSettings: [:],
211+ overrideSettings: [:],
212+ defaultSettingsWhenPrimary: [:],
213+ executableSearchPaths: realSwiftPath.dirname.relativeSubpath(from: path).map { [path.join($0).join("bin")] } ?? [],
214+ testingLibraryPlatformNames: [],
215+ fs: fs)
216+ ]
173217 }
174218}
175219
0 commit comments