Skip to content

Commit 419c192

Browse files
committed
Handle the OS version in the triple for FreeBSD
We're going to keep the versioned triple, so it needs to be passed through after all.
1 parent 6648241 commit 419c192

File tree

7 files changed

+153
-79
lines changed

7 files changed

+153
-79
lines changed

Sources/SWBAndroidPlatform/AndroidSDK.swift

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -134,30 +134,6 @@ public import Foundation
134134
case bits64 = 64
135135
}
136136

137-
@_spi(Testing) public struct LLVMTriple: Codable, Equatable, Sendable {
138-
public var arch: String
139-
public var vendor: String
140-
public var system: String
141-
public var environment: String
142-
143-
var description: String {
144-
"\(arch)-\(vendor)-\(system)-\(environment)"
145-
}
146-
147-
public init(from decoder: any Decoder) throws {
148-
let container = try decoder.singleValueContainer()
149-
let triple = try container.decode(String.self)
150-
if let match = try #/(?<arch>.+)-(?<vendor>.+)-(?<system>.+)-(?<environment>.+)/#.wholeMatch(in: triple) {
151-
self.arch = String(match.output.arch)
152-
self.vendor = String(match.output.vendor)
153-
self.system = String(match.output.system)
154-
self.environment = String(match.output.environment)
155-
} else {
156-
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid triple string: \(triple)")
157-
}
158-
}
159-
}
160-
161137
public let bitness: Bitness
162138
public let `default`: Bool
163139
public let deprecated: Bool

Sources/SWBAndroidPlatform/Plugin.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,14 @@ struct AndroidPlatformExtension: PlatformInfoExtension {
131131
let abis = androidNdk.abis
132132
let deploymentTargetRange = androidNdk.deploymentTargetRange
133133

134-
let allPossibleTriples = abis.values.flatMap { abi in
135-
(max(deploymentTargetRange.min, abi.min_os_version)...deploymentTargetRange.max).map { deploymentTarget in
134+
let allPossibleTriples = try abis.values.flatMap { abi in
135+
try (max(deploymentTargetRange.min, abi.min_os_version)...deploymentTargetRange.max).map { deploymentTarget in
136136
var triple = abi.llvm_triple
137137
triple.vendor = "unknown" // Android NDK uses "none", Swift SDKs use "unknown"
138-
triple.environment += "\(deploymentTarget)"
138+
guard let env = triple.environment else {
139+
throw StubError.error("Android triples must have an environment")
140+
}
141+
triple.environment = "\(env)\(deploymentTarget)"
139142
return triple
140143
}
141144
}.map(\.description)
@@ -173,8 +176,8 @@ struct AndroidPlatformExtension: PlatformInfoExtension {
173176
"CustomProperties": .plDict([
174177
// Unlike most platforms, the Android version goes on the environment field rather than the system field
175178
// FIXME: Make this configurable in a better way so we don't need to push build settings at the SDK definition level
176-
"LLVM_TARGET_TRIPLE_OS_VERSION": .plString("linux"),
177-
"LLVM_TARGET_TRIPLE_SUFFIX": .plString("-android$(ANDROID_DEPLOYMENT_TARGET)"),
179+
"LLVM_TARGET_TRIPLE_OS_VERSION": .plString("$(SWIFT_PLATFORM_TARGET_PREFIX)"),
180+
"LLVM_TARGET_TRIPLE_SUFFIX": .plString("-android$($(DEPLOYMENT_TARGET_SETTING_NAME))"),
178181
].merging(swiftSettings, uniquingKeysWith: { _, new in new })),
179182
"SupportedTargets": .plDict([
180183
"android": .plDict([

Sources/SWBGenericUnixPlatform/Plugin.swift

Lines changed: 91 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,44 @@ import SWBCore
1515
import 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

2558
struct GenericUnixDeveloperDirectoryExtension: DeveloperDirectoryExtension {
@@ -69,9 +102,11 @@ struct GenericUnixPlatformInfoExtension: PlatformInfoExtension {
69102
}
70103

71104
struct 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

123175
struct 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

Sources/SWBTestSupport/CoreTestSupport.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ extension Core {
5656
developerPath = .xcode(xcodeDeveloperDirPath)
5757
} else {
5858
// In the context of auto-generated package schemes, try to infer the active Xcode.
59-
let potentialDeveloperPath = getEnvironmentVariable("PATH")?.components(separatedBy: String(Path.pathEnvironmentSeparator)).first.map(Path.init)?.dirname.dirname
59+
let potentialDeveloperPath = getEnvironmentVariable(.path)?.components(separatedBy: String(Path.pathEnvironmentSeparator)).first.map(Path.init)?.dirname.dirname
6060
let versionInfo = potentialDeveloperPath?.dirname.join("version.plist")
6161
if let versionInfo = versionInfo, (try? PropertyList.fromPath(versionInfo, fs: localFS))?.dictValue?["ProjectName"] == "IDEApplication" {
6262
developerPath = potentialDeveloperPath.map { .xcode($0) }

Sources/SWBUtil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ add_library(SWBUtil
5454
LazyCache.swift
5555
Library.swift
5656
LineReader.swift
57+
LLVMTriple.swift
5758
Lock.swift
5859
MachO.swift
5960
Math.swift

Sources/SWBUtil/LLVMTriple.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
public struct LLVMTriple: Decodable, Equatable, Sendable, CustomStringConvertible {
14+
public var arch: String
15+
public var vendor: String
16+
public var system: String
17+
public var environment: String?
18+
19+
public var description: String {
20+
if let environment {
21+
return "\(arch)-\(vendor)-\(system)-\(environment)"
22+
}
23+
return "\(arch)-\(vendor)-\(system)"
24+
}
25+
26+
public init(_ string: String) throws {
27+
guard let match = try #/(?<arch>[^-]+)-(?<vendor>[^-]+)-(?<system>[^-]+)(-(?<environment>[^-]+))?/#.wholeMatch(in: string) else {
28+
throw LLVMTripleError.invalidTripleStringFormat(string)
29+
}
30+
self.arch = String(match.output.arch)
31+
self.vendor = String(match.output.vendor)
32+
self.system = String(match.output.system)
33+
self.environment = match.output.environment.map { String($0) }
34+
}
35+
36+
public init(from decoder: any Swift.Decoder) throws {
37+
self = try Self(decoder.singleValueContainer().decode(String.self))
38+
}
39+
}
40+
41+
enum LLVMTripleError: Error, CustomStringConvertible {
42+
case invalidTripleStringFormat(String)
43+
44+
var description: String {
45+
switch self {
46+
case let .invalidTripleStringFormat(tripleString):
47+
"Invalid triple string format: \(tripleString)"
48+
}
49+
}
50+
}

Sources/SWBWindowsPlatform/VSInstallation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ public struct VSInstallation: Decodable, Sendable {
5757
]
5858
let executionResult = try await Process.getOutput(url: URL(fileURLWithPath: vswhere.str), arguments: args)
5959
guard executionResult.exitStatus.isSuccess else {
60-
throw RunProcessNonZeroExitError(args: args, workingDirectory: nil, environment: [:], status: executionResult.exitStatus, stdout: ByteString(executionResult.stdout), stderr: ByteString(executionResult.stderr))
60+
throw RunProcessNonZeroExitError(args: [vswhere.str] + args, workingDirectory: nil, environment: [:], status: executionResult.exitStatus, stdout: ByteString(executionResult.stdout), stderr: ByteString(executionResult.stderr))
6161
}
6262
return try JSONDecoder().decode([VSInstallation].self, from: executionResult.stdout)
6363
}
6464

6565
private static func vswherePath(fs: any FSProxy) throws -> Path? {
6666
var paths: [Path] = []
67-
if let path = try POSIX.getenv("PATH") {
67+
if let path = getEnvironmentVariable(.path) {
6868
paths.append(contentsOf: path.split(separator: Path.pathEnvironmentSeparator).map(Path.init).filter {
6969
// PATH may contain unexpanded shell variable references
7070
$0.isAbsolute

0 commit comments

Comments
 (0)