Skip to content

Commit 365715a

Browse files
committed
Add support for generating Swift SDKs with multiple host triples
This is necessary for correctness on macOS, where the concept of multi-arch binaries exists, and all swift.org toolchains for macOS are multi-arch.
1 parent eae537f commit 365715a

File tree

4 files changed

+71
-40
lines changed

4 files changed

+71
-40
lines changed

Sources/GeneratorCLI/GeneratorCLI.swift

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,13 @@ extension GeneratorCLI {
141141
var targetSwiftPackagePath: String? = nil
142142

143143
@Option(
144+
name: .customLong("host"),
144145
help: """
145-
The host triple of the bundle. Defaults to a triple of the machine this generator is \
146-
running on if unspecified.
146+
The host triples of the bundle. Defaults to a triple or triples of the machine this generator is \
147+
running on if unspecified. Multiple host triples are only supported for macOS hosts.
147148
"""
148149
)
149-
var host: Triple? = nil
150+
var hosts: [Triple] = []
150151

151152
@Option(
152153
help:
@@ -174,19 +175,26 @@ extension GeneratorCLI {
174175
#endif
175176
}
176177

177-
func deriveHostTriple() throws -> Triple {
178-
if let host {
179-
return host
178+
func deriveHostTriples() throws -> [Triple] {
179+
if !hosts.isEmpty {
180+
return hosts
180181
}
181182
let current = try SwiftSDKGenerator.getCurrentTriple(isVerbose: self.verbose)
182183
if let arch = hostArch {
183184
let target = Triple(arch: arch, vendor: current.vendor!, os: current.os!)
184185
appLogger.warning(
185186
"deprecated: Please use `--host \(target.triple)` instead of `--host-arch \(arch)`"
186187
)
187-
return target
188+
return [target]
189+
}
190+
// macOS toolchains are built as universal binaries
191+
if current.isMacOSX {
192+
return [
193+
Triple("arm64-apple-macos"),
194+
Triple("x86_64-apple-macos"),
195+
]
188196
}
189-
return current
197+
return [current]
190198
}
191199
}
192200

@@ -230,7 +238,7 @@ extension GeneratorCLI {
230238
)
231239
var distributionVersion: String?
232240

233-
func deriveTargetTriple(hostTriple: Triple) -> Triple {
241+
func deriveTargetTriple(hostTriples: [Triple]) -> Triple {
234242
if let target = generatorOptions.target {
235243
return target
236244
}
@@ -241,7 +249,13 @@ extension GeneratorCLI {
241249
)
242250
return target
243251
}
244-
return Triple(arch: hostTriple.arch!, vendor: nil, os: .linux, environment: .gnu)
252+
let arch: Triple.Arch
253+
if hostTriples.count == 1, let hostTriple = hostTriples.first {
254+
arch = hostTriple.arch!
255+
} else {
256+
arch = try! SwiftSDKGenerator.getCurrentTriple(isVerbose: false).arch!
257+
}
258+
return Triple(arch: arch, vendor: nil, os: .linux, environment: .gnu)
245259
}
246260

247261
func run() async throws {
@@ -265,12 +279,12 @@ extension GeneratorCLI {
265279
name: distributionName,
266280
version: distributionVersion
267281
)
268-
let hostTriple = try self.generatorOptions.deriveHostTriple()
269-
let targetTriple = self.deriveTargetTriple(hostTriple: hostTriple)
282+
let hostTriples = try self.generatorOptions.deriveHostTriples()
283+
let targetTriple = self.deriveTargetTriple(hostTriples: hostTriples)
270284

271285
let recipe = try LinuxRecipe(
272286
targetTriple: targetTriple,
273-
hostTriple: hostTriple,
287+
hostTriples: hostTriples,
274288
linuxDistribution: linuxDistribution,
275289
swiftVersion: generatorOptions.swiftVersion,
276290
swiftBranch: self.generatorOptions.swiftBranch,
@@ -333,8 +347,8 @@ extension GeneratorCLI {
333347
}
334348
let recipe = try WebAssemblyRecipe(
335349
hostSwiftPackage: generatorOptions.hostSwiftPackagePath.map {
336-
let hostTriple = try self.generatorOptions.deriveHostTriple()
337-
return WebAssemblyRecipe.HostToolchainPackage(path: FilePath($0), triple: hostTriple)
350+
let hostTriples = try self.generatorOptions.deriveHostTriples()
351+
return WebAssemblyRecipe.HostToolchainPackage(path: FilePath($0), triples: hostTriples)
338352
},
339353
targetSwiftPackagePath: FilePath(targetSwiftPackagePath),
340354
wasiSysroot: FilePath(self.wasiSysroot),

Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,30 @@ struct DownloadableArtifacts: Sendable {
4444
private let paths: PathsConfiguration
4545

4646
init(
47-
hostTriple: Triple,
47+
hostTriples: [Triple],
4848
targetTriple: Triple,
4949
_ versions: VersionsConfiguration,
5050
_ paths: PathsConfiguration
5151
) throws {
5252
self.versions = versions
5353
self.paths = paths
5454

55-
if hostTriple.os == .linux {
55+
guard let hostTriple = hostTriples.first else {
56+
throw StringError("no host triples")
57+
}
58+
59+
if hostTriples.allSatisfy({ $0.os == .macosx }) {
60+
self.hostSwift = .init(
61+
remoteURL: versions.swiftDownloadURL(
62+
subdirectory: "xcode",
63+
platform: "osx",
64+
fileExtension: "pkg"
65+
),
66+
localPath: paths.artifactsCachePath
67+
.appending("host_swift_\(versions.swiftVersion)_apple-macos.pkg"),
68+
isPrebuilt: true
69+
)
70+
} else if hostTriple.os == .linux {
5671
// Amazon Linux 2 is chosen for its best compatibility with all Swift-supported Linux hosts
5772
let hostArchSuffix =
5873
hostTriple.arch == .aarch64 ? "-\(Triple.Arch.aarch64.linuxConventionName)" : ""
@@ -67,16 +82,11 @@ struct DownloadableArtifacts: Sendable {
6782
isPrebuilt: true
6883
)
6984
} else {
70-
self.hostSwift = .init(
71-
remoteURL: versions.swiftDownloadURL(
72-
subdirectory: "xcode",
73-
platform: "osx",
74-
fileExtension: "pkg"
75-
),
76-
localPath: paths.artifactsCachePath
77-
.appending("host_swift_\(versions.swiftVersion)_\(hostTriple.triple).pkg"),
78-
isPrebuilt: true
79-
)
85+
if hostTriples.count > 1 {
86+
throw StringError("unsupported host triples \(hostTriples.map { "\($0)" }.joined(separator: ", ")) (only macOS supports multiple host triples)")
87+
} else {
88+
throw StringError("unsupported host triple \(hostTriple)")
89+
}
8090
}
8191

8292
self.hostLLVM = .init(
@@ -121,3 +131,10 @@ struct DownloadableArtifacts: Sendable {
121131
)
122132
}
123133
}
134+
135+
struct StringError: Error, CustomStringConvertible {
136+
let description: String
137+
init(_ description: String) {
138+
self.description = description
139+
}
140+
}

Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ package struct LinuxRecipe: SwiftSDKRecipe {
3030
}
3131

3232
let mainTargetTriple: Triple
33-
let mainHostTriple: Triple
33+
let mainHostTriples: [Triple]
3434
let linuxDistribution: LinuxDistribution
3535
let targetSwiftSource: TargetSwiftSource
3636
let hostSwiftSource: HostSwiftSource
@@ -46,7 +46,7 @@ package struct LinuxRecipe: SwiftSDKRecipe {
4646

4747
package init(
4848
targetTriple: Triple,
49-
hostTriple: Triple,
49+
hostTriples: [Triple],
5050
linuxDistribution: LinuxDistribution,
5151
swiftVersion: String,
5252
swiftBranch: String?,
@@ -89,7 +89,7 @@ package struct LinuxRecipe: SwiftSDKRecipe {
8989

9090
self.init(
9191
mainTargetTriple: targetTriple,
92-
mainHostTriple: hostTriple,
92+
mainHostTriples: hostTriples,
9393
linuxDistribution: linuxDistribution,
9494
targetSwiftSource: targetSwiftSource,
9595
hostSwiftSource: hostSwiftSource,
@@ -100,15 +100,15 @@ package struct LinuxRecipe: SwiftSDKRecipe {
100100

101101
package init(
102102
mainTargetTriple: Triple,
103-
mainHostTriple: Triple,
103+
mainHostTriples: [Triple],
104104
linuxDistribution: LinuxDistribution,
105105
targetSwiftSource: TargetSwiftSource,
106106
hostSwiftSource: HostSwiftSource,
107107
versionsConfiguration: VersionsConfiguration,
108108
logger: Logger
109109
) {
110110
self.mainTargetTriple = mainTargetTriple
111-
self.mainHostTriple = mainHostTriple
111+
self.mainHostTriples = mainHostTriples
112112
self.linuxDistribution = linuxDistribution
113113
self.targetSwiftSource = targetSwiftSource
114114
self.hostSwiftSource = hostSwiftSource
@@ -180,7 +180,7 @@ package struct LinuxRecipe: SwiftSDKRecipe {
180180
func itemsToDownload(from artifacts: DownloadableArtifacts) -> [DownloadableArtifacts.Item] {
181181
var items: [DownloadableArtifacts.Item] = []
182182
if self.hostSwiftSource != .preinstalled
183-
&& self.mainHostTriple.os != .linux
183+
&& !self.mainHostTriples.contains(where: { $0.os == .linux })
184184
&& !self.versionsConfiguration.swiftVersion.hasPrefix("6.")
185185
{
186186
items.append(artifacts.hostLLVM)
@@ -218,7 +218,7 @@ package struct LinuxRecipe: SwiftSDKRecipe {
218218
return nil
219219
}
220220

221-
return [self.mainHostTriple]
221+
return self.mainHostTriples
222222
}
223223

224224
package func makeSwiftSDK(
@@ -240,7 +240,7 @@ package struct LinuxRecipe: SwiftSDKRecipe {
240240
try await generator.createDirectoryIfNeeded(at: sdkDirPath)
241241

242242
var downloadableArtifacts = try DownloadableArtifacts(
243-
hostTriple: mainHostTriple,
243+
hostTriples: mainHostTriples,
244244
targetTriple: generator.targetTriple,
245245
self.versionsConfiguration,
246246
generator.pathsConfiguration
@@ -335,7 +335,7 @@ package struct LinuxRecipe: SwiftSDKRecipe {
335335
}
336336

337337
if self.hostSwiftSource != .preinstalled {
338-
if self.mainHostTriple.os != .linux
338+
if !self.mainHostTriples.contains(where: { $0.os == .linux })
339339
&& !self.versionsConfiguration.swiftVersion.hasPrefix("6.")
340340
{
341341
try await generator.prepareLLDLinker(engine, llvmArtifact: downloadableArtifacts.hostLLVM)

Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ package struct WebAssemblyRecipe: SwiftSDKRecipe {
2424

2525
package struct HostToolchainPackage: Sendable {
2626
let path: FilePath
27-
let triple: Triple
27+
let triples: [Triple]
2828

29-
package init(path: FilePath, triple: Triple) {
29+
package init(path: FilePath, triples: [Triple]) {
3030
self.path = path
31-
self.triple = triple
31+
self.triples = triples
3232
}
3333
}
3434

@@ -145,7 +145,7 @@ package struct WebAssemblyRecipe: SwiftSDKRecipe {
145145
logger.info("Copying Swift binaries for the host triple...")
146146
var hostTriples: [Triple]? = nil
147147
if let hostSwiftPackage {
148-
hostTriples = [hostSwiftPackage.triple]
148+
hostTriples = hostSwiftPackage.triples
149149
try await generator.rsync(
150150
from: hostSwiftPackage.path.appending("usr"),
151151
to: pathsConfiguration.toolchainDirPath

0 commit comments

Comments
 (0)