From e4f9e54a2c35be760789171c0f96f1940bf1579b Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Fri, 29 Aug 2025 11:53:05 -0700 Subject: [PATCH] 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. --- Sources/GeneratorCLI/GeneratorCLI.swift | 62 ++++--- .../Artifacts/DownloadableArtifacts.swift | 57 ++++-- .../SwiftSDKRecipes/LinuxRecipe.swift | 18 +- .../SwiftSDKRecipes/WebAssemblyRecipe.swift | 8 +- .../ArchitectureMappingTests.swift | 4 +- .../SwiftSDKRecipes/LinuxRecipeTests.swift | 170 ++++++++++++++---- 6 files changed, 239 insertions(+), 80 deletions(-) diff --git a/Sources/GeneratorCLI/GeneratorCLI.swift b/Sources/GeneratorCLI/GeneratorCLI.swift index 6f5b24a..5394b10 100644 --- a/Sources/GeneratorCLI/GeneratorCLI.swift +++ b/Sources/GeneratorCLI/GeneratorCLI.swift @@ -141,12 +141,13 @@ extension GeneratorCLI { var targetSwiftPackagePath: String? = nil @Option( + name: .customLong("host"), help: """ - The host triple of the bundle. Defaults to a triple of the machine this generator is \ - running on if unspecified. + The host triples of the bundle. Defaults to a triple or triples of the machine this generator is \ + running on if unspecified. Multiple host triples are only supported for macOS hosts. """ ) - var host: Triple? = nil + var hosts: [Triple] = [] @Option( help: @@ -174,9 +175,9 @@ extension GeneratorCLI { #endif } - func deriveHostTriple() throws -> Triple { - if let host { - return host + func deriveHostTriples() throws -> [Triple] { + if !hosts.isEmpty { + return hosts } let current = try SwiftSDKGenerator.getCurrentTriple(isVerbose: self.verbose) if let arch = hostArch { @@ -184,9 +185,16 @@ extension GeneratorCLI { appLogger.warning( "deprecated: Please use `--host \(target.triple)` instead of `--host-arch \(arch)`" ) - return target + return [target] + } + // macOS toolchains are built as universal binaries + if current.isMacOSX { + return [ + Triple("arm64-apple-macos"), + Triple("x86_64-apple-macos"), + ] } - return current + return [current] } } @@ -230,8 +238,8 @@ extension GeneratorCLI { ) var distributionVersion: String? - func deriveTargetTriple(hostTriple: Triple) -> Triple { - if let target = generatorOptions.target { + func deriveTargetTriple(hostTriples: [Triple]) -> Triple { + if let target = generatorOptions.target, target.os == .linux { return target } if let arch = generatorOptions.targetArch { @@ -241,7 +249,13 @@ extension GeneratorCLI { ) return target } - return Triple(arch: hostTriple.arch!, vendor: nil, os: .linux, environment: .gnu) + let arch: Triple.Arch + if hostTriples.count == 1, let hostTriple = hostTriples.first { + arch = hostTriple.arch! + } else { + arch = try! SwiftSDKGenerator.getCurrentTriple(isVerbose: false).arch! + } + return Triple(arch: arch, vendor: nil, os: .linux, environment: .gnu) } func run() async throws { @@ -265,12 +279,12 @@ extension GeneratorCLI { name: distributionName, version: distributionVersion ) - let hostTriple = try self.generatorOptions.deriveHostTriple() - let targetTriple = self.deriveTargetTriple(hostTriple: hostTriple) + let hostTriples = try self.generatorOptions.deriveHostTriples() + let targetTriple = self.deriveTargetTriple(hostTriples: hostTriples) let recipe = try LinuxRecipe( targetTriple: targetTriple, - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: generatorOptions.swiftVersion, swiftBranch: self.generatorOptions.swiftBranch, @@ -331,7 +345,7 @@ extension GeneratorCLI { ) var freeBSDVersion: String - func deriveTargetTriple() throws -> Triple { + func deriveTargetTriple(hostTriples: [Triple]) throws -> Triple { if let target = generatorOptions.target, target.os == .freeBSD { return target } @@ -344,12 +358,14 @@ extension GeneratorCLI { """ ) return target + } + let arch: Triple.Arch + if hostTriples.count == 1, let hostTriple = hostTriples.first { + arch = hostTriple.arch! } else { - // If no target is given, use the architecture of the host. - let hostTriple = try self.generatorOptions.deriveHostTriple() - let hostArch = hostTriple.arch! - return Triple(arch: hostArch, vendor: nil, os: .freeBSD) + arch = try! SwiftSDKGenerator.getCurrentTriple(isVerbose: false).arch! } + return Triple(arch: arch, vendor: nil, os: .freeBSD) } func run() async throws { @@ -358,8 +374,8 @@ extension GeneratorCLI { throw StringError("Only FreeBSD versions 14.3 or higher are supported.") } - let hostTriple = try self.generatorOptions.deriveHostTriple() - let targetTriple = try self.deriveTargetTriple() + let hostTriples = try self.generatorOptions.deriveHostTriples() + let targetTriple = try self.deriveTargetTriple(hostTriples: hostTriples) let sourceSwiftToolchain: FilePath? if let fromSwiftToolchain { @@ -411,8 +427,8 @@ extension GeneratorCLI { } let recipe = try WebAssemblyRecipe( hostSwiftPackage: generatorOptions.hostSwiftPackagePath.map { - let hostTriple = try self.generatorOptions.deriveHostTriple() - return WebAssemblyRecipe.HostToolchainPackage(path: FilePath($0), triple: hostTriple) + let hostTriples = try self.generatorOptions.deriveHostTriples() + return WebAssemblyRecipe.HostToolchainPackage(path: FilePath($0), triples: hostTriples) }, targetSwiftPackagePath: FilePath(targetSwiftPackagePath), wasiSysroot: FilePath(self.wasiSysroot), diff --git a/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift b/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift index 1af7fd1..17169fa 100644 --- a/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift +++ b/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift @@ -18,6 +18,8 @@ import struct SystemPackage.FilePath extension Triple { fileprivate var llvmBinaryURLSuffix: String { switch (self.os, self.arch) { + case (.win32, .aarch64): return "aarch64-pc-windows-msvc" + case (.win32, .x86_64): return "x86_64-pc-windows-msvc" case (.linux, .aarch64): return "aarch64-linux-gnu" case (.linux, .x86_64): return "x86_64-linux-gnu-ubuntu-22.04" case (.macosx, .aarch64): return "arm64-apple-darwin22.0" @@ -30,6 +32,27 @@ extension Triple { typealias CPUMapping = [Triple.Arch: String] struct DownloadableArtifacts: Sendable { + enum Error: Swift.Error, CustomStringConvertible { + case noHostTriples + case unsupportedHostTriple(Triple) + case unsupportedHostTriples([Triple]) + + var description: String { + switch self { + case .noHostTriples: + "no host triples" + case let .unsupportedHostTriple(hostTriple): + "unsupported host triple \(hostTriple)" + case let .unsupportedHostTriples(hostTriples): + """ + unsupported host triples \( + hostTriples.map { "\($0)" }.joined(separator: ", ") + ) (only macOS supports multiple host triples) + """ + } + } + } + struct Item: Sendable, CacheKey { let remoteURL: URL var localPath: FilePath @@ -44,7 +67,7 @@ struct DownloadableArtifacts: Sendable { private let paths: PathsConfiguration init( - hostTriple: Triple, + hostTriples: [Triple], targetTriple: Triple, _ versions: VersionsConfiguration, _ paths: PathsConfiguration @@ -52,7 +75,22 @@ struct DownloadableArtifacts: Sendable { self.versions = versions self.paths = paths - if hostTriple.os == .linux { + guard let hostTriple = hostTriples.first else { + throw Error.noHostTriples + } + + if hostTriples.allSatisfy({ $0.os == .macosx }) { + self.hostSwift = .init( + remoteURL: versions.swiftDownloadURL( + subdirectory: "xcode", + platform: "osx", + fileExtension: "pkg" + ), + localPath: paths.artifactsCachePath + .appending("host_swift_\(versions.swiftVersion)_apple-macos.pkg"), + isPrebuilt: true + ) + } else if hostTriple.os == .linux && hostTriples.count == 1 { // Amazon Linux 2 is chosen for its best compatibility with all Swift-supported Linux hosts let hostArchSuffix = hostTriple.arch == .aarch64 ? "-\(Triple.Arch.aarch64.linuxConventionName)" : "" @@ -67,16 +105,11 @@ struct DownloadableArtifacts: Sendable { isPrebuilt: true ) } else { - self.hostSwift = .init( - remoteURL: versions.swiftDownloadURL( - subdirectory: "xcode", - platform: "osx", - fileExtension: "pkg" - ), - localPath: paths.artifactsCachePath - .appending("host_swift_\(versions.swiftVersion)_\(hostTriple.triple).pkg"), - isPrebuilt: true - ) + if hostTriples.count > 1 { + throw Error.unsupportedHostTriples(hostTriples) + } else { + throw Error.unsupportedHostTriple(hostTriple) + } } self.hostLLVM = .init( diff --git a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift index af3ecc4..3849bdf 100644 --- a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift +++ b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift @@ -30,7 +30,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { } let mainTargetTriple: Triple - let mainHostTriple: Triple + let mainHostTriples: [Triple] let linuxDistribution: LinuxDistribution let targetSwiftSource: TargetSwiftSource let hostSwiftSource: HostSwiftSource @@ -46,7 +46,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { package init( targetTriple: Triple, - hostTriple: Triple, + hostTriples: [Triple], linuxDistribution: LinuxDistribution, swiftVersion: String, swiftBranch: String?, @@ -89,7 +89,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { self.init( mainTargetTriple: targetTriple, - mainHostTriple: hostTriple, + mainHostTriples: hostTriples, linuxDistribution: linuxDistribution, targetSwiftSource: targetSwiftSource, hostSwiftSource: hostSwiftSource, @@ -100,7 +100,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { package init( mainTargetTriple: Triple, - mainHostTriple: Triple, + mainHostTriples: [Triple], linuxDistribution: LinuxDistribution, targetSwiftSource: TargetSwiftSource, hostSwiftSource: HostSwiftSource, @@ -108,7 +108,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { logger: Logger ) { self.mainTargetTriple = mainTargetTriple - self.mainHostTriple = mainHostTriple + self.mainHostTriples = mainHostTriples self.linuxDistribution = linuxDistribution self.targetSwiftSource = targetSwiftSource self.hostSwiftSource = hostSwiftSource @@ -180,7 +180,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { func itemsToDownload(from artifacts: DownloadableArtifacts) -> [DownloadableArtifacts.Item] { var items: [DownloadableArtifacts.Item] = [] if self.hostSwiftSource != .preinstalled - && self.mainHostTriple.os != .linux + && !self.mainHostTriples.contains(where: { $0.os == .linux }) && !self.versionsConfiguration.swiftVersion.hasPrefix("6.") { items.append(artifacts.hostLLVM) @@ -218,7 +218,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { return nil } - return [self.mainHostTriple] + return self.mainHostTriples } package func makeSwiftSDK( @@ -240,7 +240,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { try await generator.createDirectoryIfNeeded(at: sdkDirPath) var downloadableArtifacts = try DownloadableArtifacts( - hostTriple: mainHostTriple, + hostTriples: mainHostTriples, targetTriple: generator.targetTriple, self.versionsConfiguration, generator.pathsConfiguration @@ -335,7 +335,7 @@ package struct LinuxRecipe: SwiftSDKRecipe { } if self.hostSwiftSource != .preinstalled { - if self.mainHostTriple.os != .linux + if !self.mainHostTriples.contains(where: { $0.os == .linux }) && !self.versionsConfiguration.swiftVersion.hasPrefix("6.") { try await generator.prepareLLDLinker(engine, llvmArtifact: downloadableArtifacts.hostLLVM) diff --git a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift index 0e3d956..84996a6 100644 --- a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift +++ b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift @@ -24,11 +24,11 @@ package struct WebAssemblyRecipe: SwiftSDKRecipe { package struct HostToolchainPackage: Sendable { let path: FilePath - let triple: Triple + let triples: [Triple] - package init(path: FilePath, triple: Triple) { + package init(path: FilePath, triples: [Triple]) { self.path = path - self.triple = triple + self.triples = triples } } @@ -145,7 +145,7 @@ package struct WebAssemblyRecipe: SwiftSDKRecipe { logger.info("Copying Swift binaries for the host triple...") var hostTriples: [Triple]? = nil if let hostSwiftPackage { - hostTriples = [hostSwiftPackage.triple] + hostTriples = hostSwiftPackage.triples try await generator.rsync( from: hostSwiftPackage.path.appending("usr"), to: pathsConfiguration.toolchainDirPath diff --git a/Tests/SwiftSDKGeneratorTests/ArchitectureMappingTests.swift b/Tests/SwiftSDKGeneratorTests/ArchitectureMappingTests.swift index 893d8c7..ba76c11 100644 --- a/Tests/SwiftSDKGeneratorTests/ArchitectureMappingTests.swift +++ b/Tests/SwiftSDKGeneratorTests/ArchitectureMappingTests.swift @@ -49,7 +49,7 @@ final class ArchitectureMappingTests: XCTestCase { ) async throws { let recipe = try LinuxRecipe( targetTriple: targetTriple, - hostTriple: hostTriple, + hostTriples: [hostTriple], linuxDistribution: .ubuntu(.jammy), swiftVersion: "5.8-RELEASE", swiftBranch: nil, @@ -79,7 +79,7 @@ final class ArchitectureMappingTests: XCTestCase { // Verify download URLs let artifacts = try await DownloadableArtifacts( - hostTriple: hostTriple, + hostTriples: [hostTriple], targetTriple: sdk.targetTriple, recipe.versionsConfiguration, sdk.pathsConfiguration diff --git a/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift b/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift index b57807e..b41d0ea 100644 --- a/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift +++ b/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift @@ -19,7 +19,7 @@ final class LinuxRecipeTests: XCTestCase { let logger = Logger(label: "LinuxRecipeTests") func createRecipe( - hostTriple: Triple = Triple("x86_64-unknown-linux-gnu"), + hostTriples: [Triple] = [Triple("x86_64-unknown-linux-gnu")], linuxDistribution: LinuxDistribution, swiftVersion: String = "6.0", withDocker: Bool = false, @@ -30,7 +30,7 @@ final class LinuxRecipeTests: XCTestCase { ) throws -> LinuxRecipe { try LinuxRecipe( targetTriple: Triple("aarch64-unknown-linux-gnu"), - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: swiftVersion, swiftBranch: nil, @@ -132,7 +132,7 @@ final class LinuxRecipeTests: XCTestCase { targetTriple: recipe.mainTargetTriple ) let downloadableArtifacts = try DownloadableArtifacts( - hostTriple: recipe.mainHostTriple, + hostTriples: recipe.mainHostTriples, targetTriple: recipe.mainTargetTriple, recipe.versionsConfiguration, pathsConfiguration @@ -154,8 +154,44 @@ final class LinuxRecipeTests: XCTestCase { XCTAssertEqual(foundHostSwift, includesHostSwift) } - func testItemsToDownloadForMacOSHost() throws { - let hostTriple = Triple("x86_64-apple-macos") + func testItemsToDownloadForMacOSHost_noArchs() throws { + try testItemsToDownloadForMacOSHost(hostTriples: []) { result in + XCTAssertThrowsError( + try result.get(), + "", + { error in + if case DownloadableArtifacts.Error.noHostTriples = error { + return + } + XCTFail("unexpected error: \(error)") + } + ) + } + } + + func testItemsToDownloadForMacOSHost_arm64() throws { + try testItemsToDownloadForMacOSHost(hostTriples: [Triple("arm64-apple-macos")]) + } + + func testItemsToDownloadForMacOSHost_x86_64() throws { + try testItemsToDownloadForMacOSHost(hostTriples: [Triple("x86_64-apple-macos")]) + } + + func testItemsToDownloadForMacOSHost_multiArch() throws { + try testItemsToDownloadForMacOSHost( + hostTriples: [Triple("arm64-apple-macos"), Triple("x86_64-apple-macos")] + ) + } + + /// Runs a series of test cases with expectation for a macOS host. + /// - parameter hostTriples: The list of host triples that the generated SDK should be compatible with. + /// - parameter validate: A function to validate the result of each test case - this is a `Result` + /// in order to allow clients to either expect that the test case did not throw an error (succeeded), + /// or that it did throw an error (expected failure). + private func testItemsToDownloadForMacOSHost( + hostTriples: [Triple], + validate: ((Result) throws -> Void)? = nil + ) throws { let linuxDistribution = try LinuxDistribution(name: .ubuntu, version: "22.04") let testCases: [( @@ -165,7 +201,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Remote tarballs on Swift < 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "5.10" ), @@ -176,7 +212,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Remote tarballs on Swift >= 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "6.0" ), @@ -187,7 +223,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Remote target tarball with preinstalled toolchain recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "5.9", includeHostToolchain: false @@ -199,7 +235,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Local packages with Swift < 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "5.10", hostSwiftPackagePath: "/path/to/host/swift", @@ -212,7 +248,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Local packages with Swift >= 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "6.0", hostSwiftPackagePath: "/path/to/host/swift", @@ -225,23 +261,30 @@ final class LinuxRecipeTests: XCTestCase { ] for testCase in testCases { - try runItemsToDownloadTestCase( - recipe: testCase.recipe, - includesHostLLVM: testCase.includesHostLLVM, - includesTargetSwift: testCase.includesTargetSwift, - includesHostSwift: testCase.includesHostSwift - ) + let result = Result { + try runItemsToDownloadTestCase( + recipe: testCase.recipe, + includesHostLLVM: testCase.includesHostLLVM, + includesTargetSwift: testCase.includesTargetSwift, + includesHostSwift: testCase.includesHostSwift + ) + } + if let validate { + try validate(result) + } else { + try result.get() + } } } func testItemsToDownloadForLinuxHost() throws { - let hostTriple = Triple("x86_64-unknown-linux-gnu") + let hostTriples = [Triple("x86_64-unknown-linux-gnu")] let linuxDistribution = try LinuxDistribution(name: .ubuntu, version: "22.04") let testCases = [ ( // Remote tarballs on Swift < 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "5.10" ), @@ -251,7 +294,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Remote tarballs on Swift >= 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "6.0" ), @@ -261,7 +304,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Remote target tarball with preinstalled toolchain recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "5.9", includeHostToolchain: false @@ -272,7 +315,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Local packages with Swift < 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "5.10", hostSwiftPackagePath: "/path/to/host/swift", @@ -284,7 +327,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Local packages with Swift >= 6.0 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: linuxDistribution, swiftVersion: "6.0", hostSwiftPackagePath: "/path/to/host/swift", @@ -305,14 +348,81 @@ final class LinuxRecipeTests: XCTestCase { } } + func testItemsToDownloadForLinuxMultiHost() throws { + let hostTriples = [Triple("aarch64-unknown-linux-gnu"), Triple("x86_64-unknown-linux-gnu")] + let linuxDistribution = try LinuxDistribution(name: .ubuntu, version: "22.04") + XCTAssertThrowsError( + try runItemsToDownloadTestCase( + recipe: createRecipe( + hostTriples: hostTriples, + linuxDistribution: linuxDistribution, + swiftVersion: "5.10" + ), + includesHostLLVM: false, // when host is Linux we do not download LLVM + includesTargetSwift: true, + includesHostSwift: true + ), + "" + ) { error in + if case DownloadableArtifacts.Error.unsupportedHostTriples(hostTriples) = error { + return + } + XCTFail("unexpected error: \(error)") + } + } + + func testItemsToDownloadForUnsupportedHost() throws { + let linuxDistribution = try LinuxDistribution(name: .ubuntu, version: "22.04") + + let hostTriple = Triple("x86_64-pc-windows-msvc") + XCTAssertThrowsError( + try runItemsToDownloadTestCase( + recipe: createRecipe( + hostTriples: [hostTriple], + linuxDistribution: linuxDistribution, + swiftVersion: "5.10" + ), + includesHostLLVM: false, + includesTargetSwift: true, + includesHostSwift: true + ), + "" + ) { error in + if case DownloadableArtifacts.Error.unsupportedHostTriple(hostTriple) = error { + return + } + XCTFail("unexpected error: \(error)") + } + + let hostTriples = [Triple("aarch64-pc-windows-msvc"), Triple("x86_64-pc-windows-msvc")] + XCTAssertThrowsError( + try runItemsToDownloadTestCase( + recipe: createRecipe( + hostTriples: hostTriples, + linuxDistribution: linuxDistribution, + swiftVersion: "5.10" + ), + includesHostLLVM: false, + includesTargetSwift: true, + includesHostSwift: true + ), + "" + ) { error in + if case DownloadableArtifacts.Error.unsupportedHostTriples(hostTriples) = error { + return + } + XCTFail("unexpected error: \(error)") + } + } + // Ubuntu toolchains will be selected for Debian 11 and 12 depending on the Swift version func testItemsToDownloadForDebianTargets() throws { - let hostTriple = Triple("x86_64-unknown-linux-gnu") + let hostTriples = [Triple("x86_64-unknown-linux-gnu")] let testCases = [ ( // Debian 11 -> ubuntu20.04 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: try LinuxDistribution(name: .debian, version: "11"), swiftVersion: "5.9" ), @@ -321,7 +431,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Debian 12 with Swift 5.9 -> ubuntu22.04 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: try LinuxDistribution(name: .debian, version: "12"), swiftVersion: "5.9" ), @@ -330,7 +440,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Debian 12 with Swift 5.10 -> ubuntu22.04 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: try LinuxDistribution(name: .debian, version: "12"), swiftVersion: "5.10" ), @@ -339,7 +449,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Debian 11 with Swift 6.0 -> ubuntu20.04 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: try LinuxDistribution(name: .debian, version: "11"), swiftVersion: "6.0" ), @@ -348,7 +458,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Debian 12 with Swift 5.10.1 -> debian12 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: try LinuxDistribution(name: .debian, version: "12"), swiftVersion: "5.10.1" ), @@ -357,7 +467,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Debian 12 with Swift 6.0 -> debian12 recipe: try createRecipe( - hostTriple: hostTriple, + hostTriples: hostTriples, linuxDistribution: try LinuxDistribution(name: .debian, version: "12"), swiftVersion: "6.0" ), @@ -373,7 +483,7 @@ final class LinuxRecipeTests: XCTestCase { targetTriple: testCase.recipe.mainTargetTriple ) let downloadableArtifacts = try DownloadableArtifacts( - hostTriple: testCase.recipe.mainHostTriple, + hostTriples: testCase.recipe.mainHostTriples, targetTriple: testCase.recipe.mainTargetTriple, testCase.recipe.versionsConfiguration, pathsConfiguration