Skip to content

Commit f63f812

Browse files
Add new options that control whether host toolchain is included (#165)
This adds a new `--no-host-toolchain` flag to the `make-linux-sdk` sub-command, making it possible to generate an SDK for x86_64 or aarch64 with only the target sysroot and Swift libraries, like this: ```bash # x86_64 swift run swift-sdk-generator make-linux-sdk --swift-version 6.0.3-RELEASE --target x86_64-unknown-linux-gnu --no-include-host-toolchain # aarch64 swift run swift-sdk-generator make-linux-sdk --swift-version 6.0.3-RELEASE --target aarch64-unknown-linux-gnu --no-include-host-toolchain ``` I tested the generated SDKs on both Ubuntu 22.04 and macOS 15 and they work just fine. Ubuntu x86_64 -> aarch64: ```bash > swift build --swift-sdk 6.0.3-RELEASE_ubuntu_jammy_aarch64 Building for debugging... warning: Could not read SDKSettings.json for SDK at: ~/.swiftpm/swift-sdks/6.0.3-RELEASE_ubuntu_jammy_aarch64.artifactbundle/6.0.3-RELEASE_ubuntu_jammy_aarch64/aarch64-unknown-linux-gnu/ubuntu-jammy.sdk [485/485] Linking ConsumePublishServices Build complete! (25.37s) ``` macOS arm64 -> x86_64: ```bash > swift build --swift-sdk 6.0.3-RELEASE_ubuntu_jammy_x86_64 Building for debugging... warning: Could not read SDKSettings.json for SDK at: /Users/xtremek/Library/org.swift.swiftpm/swift-sdks/6.0.3-RELEASE_ubuntu_jammy_x86_64.artifactbundle/6.0.3-RELEASE_ubuntu_jammy_x86_64/x86_64-unknown-linux-gnu/ubuntu-jammy.sdk <unknown>:0: warning: libc not found for 'x86_64-unknown-linux-gnu'; C stdlib may be unavailable [1171/1171] Linking ConsumePublishServices Build complete! (39.43s) ```
1 parent 6517aa2 commit f63f812

File tree

9 files changed

+273
-47
lines changed

9 files changed

+273
-47
lines changed

Sources/GeneratorCLI/GeneratorCLI.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ extension GeneratorCLI {
107107
)
108108
var hostSwiftPackagePath: String? = nil
109109

110+
@Flag(
111+
inversion: .prefixedNo,
112+
help: """
113+
Whether or not to include the host toolchain in the Swift SDK.
114+
If the host toolchain is not included, this makes the Swift SDK compatible with any host, \
115+
but requires exactly the same version of the swift.org toolchain to be installed for it to work.
116+
"""
117+
)
118+
var hostToolchain: Bool = true
119+
110120
@Option(
111121
help: """
112122
Path to the Swift toolchain package containing the Swift standard library that runs on the target platform.
@@ -225,7 +235,8 @@ extension GeneratorCLI {
225235
withDocker: self.withDocker,
226236
fromContainerImage: self.fromContainerImage,
227237
hostSwiftPackagePath: self.generatorOptions.hostSwiftPackagePath,
228-
targetSwiftPackagePath: self.generatorOptions.targetSwiftPackagePath
238+
targetSwiftPackagePath: self.generatorOptions.targetSwiftPackagePath,
239+
includeHostToolchain: self.generatorOptions.hostToolchain
229240
)
230241
try await GeneratorCLI.run(recipe: recipe, targetTriple: targetTriple, options: self.generatorOptions)
231242
}

Sources/Helpers/Vendor/Triple.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
///
3333
/// This is a port of https://github.com/apple/swift-llvm/blob/stable/include/llvm/ADT/Triple.h
3434
@dynamicMemberLookup
35-
public struct Triple: Sendable {
35+
public struct Triple: Sendable, Equatable {
3636
/// `Triple` proxies predicates from `Triple.OS`, returning `false` for an unknown OS.
3737
public subscript(dynamicMember predicate: KeyPath<OS, Bool>) -> Bool {
3838
os?[keyPath: predicate] ?? false

Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Download.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ extension SwiftSDKGenerator {
109109
}
110110

111111
print("Downloading \(urls.count) Ubuntu packages...")
112-
let pathsConfiguration = self.pathsConfiguration
113-
114112
try await inTemporaryDirectory { fs, tmpDir in
115113
let downloadedFiles = try await self.downloadFiles(from: urls, to: tmpDir, client, engine)
116114
report(downloadedFiles: downloadedFiles)
@@ -119,8 +117,6 @@ extension SwiftSDKGenerator {
119117
try await fs.unpack(file: tmpDir.appending(fileName), into: sdkDirPath)
120118
}
121119
}
122-
123-
try createDirectoryIfNeeded(at: pathsConfiguration.toolchainBinDirPath)
124120
}
125121

126122
func downloadFiles(

Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Entrypoint.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,10 @@ public extension SwiftSDKGenerator {
4646
}
4747

4848
try await self.createDirectoryIfNeeded(at: pathsConfiguration.artifactsCachePath)
49-
try await self.createDirectoryIfNeeded(at: pathsConfiguration.toolchainDirPath)
5049

5150
let swiftSDKProduct = try await recipe.makeSwiftSDK(generator: self, engine: engine, httpClient: client)
5251

53-
let toolsetJSONPath = try await generateToolsetJSON(recipe: recipe)
52+
let toolsetJSONPath = try await self.generateToolsetJSON(recipe: recipe)
5453

5554
try await generateDestinationJSON(
5655
toolsetPath: toolsetJSONPath,

Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Unpack.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ extension SwiftSDKGenerator {
4646
logGenerationStep("Unpacking and copying Swift binaries for the host triple...")
4747
let pathsConfiguration = self.pathsConfiguration
4848

49+
try self.createDirectoryIfNeeded(at: pathsConfiguration.toolchainDirPath)
50+
4951
let excludes =
5052
unusedDarwinPlatforms.map { "--exclude usr/lib/swift/\($0)" } +
5153
unusedDarwinPlatforms.map { "--exclude usr/lib/swift_static/\($0)" } +

Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public actor SwiftSDKGenerator {
7070
let darwinTriple = Triple("\(cpu)-apple-darwin\(darwinVersion)")
7171
return Triple("\(cpu)-apple-macos\(darwinTriple._macOSVersion?.description ?? "")")
7272
#elseif os(Linux)
73-
return Triple("\(cpu)-unknown-linux")
73+
return Triple("\(cpu)-unknown-linux-gnu")
7474
#else
7575
fatalError("Triple detection not implemented for the platform that this generator was built on.")
7676
#endif

Sources/SwiftSDKGenerator/Serialization/Toolset.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public struct Toolset: Encodable {
2626

2727
/// Root path of the toolset, if present. When filling in ``Toolset.ToolProperties/path``, if a raw path string in
2828
/// ``DecodedToolset`` is inferred to be relative, it's resolved as absolute path relatively to `rootPath`.
29-
let rootPath: String?
29+
var rootPath: String?
3030

3131
// MARK: Tools currently known and used by SwiftPM.
3232

Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift

Lines changed: 75 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ public struct LinuxRecipe: SwiftSDKRecipe {
2121
case remoteTarball
2222
}
2323

24-
public enum HostSwiftSource: Sendable {
24+
public enum HostSwiftSource: Sendable, Equatable {
2525
case localPackage(FilePath)
2626
case remoteTarball
27+
case preinstalled
2728
}
2829

2930
let mainTargetTriple: Triple
@@ -50,7 +51,8 @@ public struct LinuxRecipe: SwiftSDKRecipe {
5051
withDocker: Bool,
5152
fromContainerImage: String?,
5253
hostSwiftPackagePath: String?,
53-
targetSwiftPackagePath: String?
54+
targetSwiftPackagePath: String?,
55+
includeHostToolchain: Bool = false
5456
) throws {
5557
let versionsConfiguration = try VersionsConfiguration(
5658
swiftVersion: swiftVersion,
@@ -72,7 +74,9 @@ public struct LinuxRecipe: SwiftSDKRecipe {
7274
}
7375
}
7476
let hostSwiftSource: HostSwiftSource
75-
if let hostSwiftPackagePath {
77+
if includeHostToolchain == false {
78+
hostSwiftSource = .preinstalled
79+
} else if let hostSwiftPackagePath {
7680
hostSwiftSource = .localPackage(FilePath(hostSwiftPackagePath))
7781
} else {
7882
hostSwiftSource = .remoteTarball
@@ -105,6 +109,10 @@ public struct LinuxRecipe: SwiftSDKRecipe {
105109
}
106110

107111
public func applyPlatformOptions(toolset: inout Toolset, targetTriple: Triple) {
112+
if self.hostSwiftSource == .preinstalled {
113+
toolset.rootPath = nil
114+
}
115+
108116
var swiftCompilerOptions = ["-Xlinker", "-R/usr/lib/swift/linux/"]
109117

110118
// Swift 5.9 does not handle the `-use-ld` option properly:
@@ -113,7 +121,10 @@ public struct LinuxRecipe: SwiftSDKRecipe {
113121
swiftCompilerOptions += ["-Xclang-linker", "--ld-path=ld.lld"]
114122
} else {
115123
swiftCompilerOptions.append("-use-ld=lld")
116-
toolset.linker = Toolset.ToolProperties(path: "ld.lld")
124+
125+
if self.hostSwiftSource != .preinstalled {
126+
toolset.linker = Toolset.ToolProperties(path: "ld.lld")
127+
}
117128
}
118129

119130
toolset.swiftCompiler = Toolset.ToolProperties(extraCLIOptions: swiftCompilerOptions)
@@ -151,6 +162,48 @@ public struct LinuxRecipe: SwiftSDKRecipe {
151162
.appending("\(self.linuxDistribution.name.rawValue)-\(self.linuxDistribution.release).sdk")
152163
}
153164

165+
func itemsToDownload(from artifacts: DownloadableArtifacts) -> [DownloadableArtifacts.Item] {
166+
var items: [DownloadableArtifacts.Item] = []
167+
if self.hostSwiftSource != .preinstalled && !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") {
168+
items.append(artifacts.hostLLVM)
169+
}
170+
171+
switch self.targetSwiftSource {
172+
case .remoteTarball:
173+
items.append(artifacts.targetSwift)
174+
case .docker, .localPackage: break
175+
}
176+
177+
switch self.hostSwiftSource {
178+
case .remoteTarball:
179+
items.append(artifacts.hostSwift)
180+
case .localPackage: break
181+
case .preinstalled: break
182+
}
183+
return items
184+
}
185+
186+
var hostTriples: [Triple]? {
187+
if self.hostSwiftSource == .preinstalled {
188+
// Swift 5.9 and 5.10 require `supportedTriples` to be set in info.json.
189+
// FIXME: This can be removed once the SDK generator does not support 5.9/5.10 any more.
190+
if self.versionsConfiguration.swiftVersion.hasPrefix("5.9")
191+
|| self.versionsConfiguration.swiftVersion.hasPrefix("5.10") {
192+
return [
193+
Triple("x86_64-unknown-linux-gnu"),
194+
Triple("aarch64-unknown-linux-gnu"),
195+
Triple("x86_64-apple-macos"),
196+
Triple("arm64-apple-macos"),
197+
]
198+
}
199+
200+
// Swift 6.0 and later can set `supportedTriples` to nil
201+
return nil
202+
}
203+
204+
return [self.mainHostTriple]
205+
}
206+
154207
public func makeSwiftSDK(
155208
generator: SwiftSDKGenerator,
156209
engine: QueryEngine,
@@ -173,26 +226,7 @@ public struct LinuxRecipe: SwiftSDKRecipe {
173226
client,
174227
engine,
175228
downloadableArtifacts: &downloadableArtifacts,
176-
itemsToDownload: { artifacts in
177-
var items: [DownloadableArtifacts.Item] = []
178-
179-
if !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") {
180-
items.append(artifacts.hostLLVM)
181-
}
182-
183-
switch self.targetSwiftSource {
184-
case .remoteTarball:
185-
items.append(artifacts.targetSwift)
186-
case .docker, .localPackage: break
187-
}
188-
189-
switch self.hostSwiftSource {
190-
case .remoteTarball:
191-
items.append(artifacts.hostSwift)
192-
case .localPackage: break
193-
}
194-
return items
195-
}
229+
itemsToDownload: { artifacts in itemsToDownload(from: artifacts) }
196230
)
197231

198232
if !self.shouldUseDocker {
@@ -219,6 +253,8 @@ public struct LinuxRecipe: SwiftSDKRecipe {
219253
try await generator.unpackHostSwift(
220254
hostSwiftPackagePath: downloadableArtifacts.hostSwift.localPath
221255
)
256+
case .preinstalled:
257+
break
222258
}
223259

224260
switch self.targetSwiftSource {
@@ -240,24 +276,26 @@ public struct LinuxRecipe: SwiftSDKRecipe {
240276
)
241277
}
242278

243-
if !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") {
244-
try await generator.prepareLLDLinker(engine, llvmArtifact: downloadableArtifacts.hostLLVM)
245-
}
246-
247279
try await generator.fixAbsoluteSymlinks(sdkDirPath: sdkDirPath)
248280

249-
if self.versionsConfiguration.swiftVersion.hasPrefix("5.9") ||
250-
self.versionsConfiguration.swiftVersion .hasPrefix("5.10") {
251-
try await generator.symlinkClangHeaders()
252-
}
281+
if self.hostSwiftSource != .preinstalled {
282+
if !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") {
283+
try await generator.prepareLLDLinker(engine, llvmArtifact: downloadableArtifacts.hostLLVM)
284+
}
253285

254-
let autolinkExtractPath = generator.pathsConfiguration.toolchainBinDirPath.appending("swift-autolink-extract")
286+
if self.versionsConfiguration.swiftVersion.hasPrefix("5.9") ||
287+
self.versionsConfiguration.swiftVersion .hasPrefix("5.10") {
288+
try await generator.symlinkClangHeaders()
289+
}
290+
291+
let autolinkExtractPath = generator.pathsConfiguration.toolchainBinDirPath.appending("swift-autolink-extract")
255292

256-
if await !generator.doesFileExist(at: autolinkExtractPath) {
257-
logGenerationStep("Fixing `swift-autolink-extract` symlink...")
258-
try await generator.createSymlink(at: autolinkExtractPath, pointingTo: "swift")
293+
if await !generator.doesFileExist(at: autolinkExtractPath) {
294+
logGenerationStep("Fixing `swift-autolink-extract` symlink...")
295+
try await generator.createSymlink(at: autolinkExtractPath, pointingTo: "swift")
296+
}
259297
}
260298

261-
return SwiftSDKProduct(sdkDirPath: sdkDirPath, hostTriples: [self.mainHostTriple])
299+
return SwiftSDKProduct(sdkDirPath: sdkDirPath, hostTriples: self.hostTriples)
262300
}
263301
}

0 commit comments

Comments
 (0)