From 84d62bf5db1b9741310be769d85bff4c0fec377d Mon Sep 17 00:00:00 2001 From: "Jesse L. Zamora" Date: Thu, 16 Jan 2025 12:45:10 -0500 Subject: [PATCH] Build Swift SDKs for a Linux host if the `--host` parameter matches a Linux OS (`*-unknown-linux-gnu`) (#167) This fixes #114 and provides the following: - If the `--host` param or auto-detected `hostTriple.os` is `.linux`, the amazonlinux2 Swift toolchain is downloaded and included in the Swift SDK. Examples: ``` swift run swift-sdk-generator make-linux-sdk --swift-version 6.0.3-RELEASE --host x86_64-unknown-linux-gnu --target aarch64-unknown-linux-gnu swift run swift-sdk-generator make-linux-sdk --swift-version 5.10.1-RELEASE --host aarch64-unknown-linux-gnu --target x86_64-unknown-linux-gnu ``` - I chose `amazonlinux2` for the host toolchain as it seems to be compatible with *every* Swift-supported Linux distribution with glibc versions and included libraries. - Updated the README.md to show that Ubuntu, RHEL, Amazon Linux 2, and Debian are officially supported as hosts and somewhat supported as targets... :) For testing all of this, I updated the EndToEndTests: - If the`SWIFT_SDK_GENERATOR_TEST_LINUX_SWIFT_SDKS` env variable is defined, Swift SDKs are built for a Linux host with the arch matching the machine on which the tests are running. So on an M-series Mac, the triple `aarch64-unknown-linux-gnu` is used. Or on an Intel Mac or PC, then `x86_64-unknown-linux-gnu` is used as the `--host` triple. - When Linux Swift SDKs are being tested, then a matrix of Swift docker containers are run against each test case to ensure the SDK works on every Linux distribution: ``` [SwiftSDKGeneratorTests] Creating test project /tmp/FDFD488C-089B-4213-B927-0DE0F9BD6B3A/swift-sdk-generator-test [SwiftSDKGeneratorTests] Updating minimum swift-tools-version in test project... [SwiftSDKGeneratorTests] Building test project in 6.0-focal container [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-focal container with static-swift-stdlib [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-jammy container [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-jammy container with static-swift-stdlib [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-noble container [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-noble container with static-swift-stdlib [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-fedora39 container [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-fedora39 container with static-swift-stdlib [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-rhel-ubi9 container [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-rhel-ubi9 container with static-swift-stdlib [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-amazonlinux2 container [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-amazonlinux2 container with static-swift-stdlib [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-bookworm container [SwiftSDKGeneratorTests] Test project built successfully [SwiftSDKGeneratorTests] Building test project in 6.0-bookworm container with static-swift-stdlib [SwiftSDKGeneratorTests] Test project built successfully ``` --- README.md | 9 +- .../Artifacts/DownloadableArtifacts.swift | 35 ++++-- .../Generator/SwiftSDKGenerator+Fixup.swift | 12 +- .../Generator/SwiftSDKGenerator+Unpack.swift | 33 +++-- .../SwiftSDKRecipes/LinuxRecipe.swift | 8 +- .../SwiftSDKRecipes/WebAssemblyRecipe.swift | 2 +- .../EndToEndTests.swift | 90 +++++++++++--- .../SwiftSDKRecipes/LinuxRecipeTests.swift | 115 ++++++++++++++---- 8 files changed, 235 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index af6ac89..0e723e9 100644 --- a/README.md +++ b/README.md @@ -37,13 +37,16 @@ Linux distributions officially supported by the Swift project. | -: | :- | :- | | macOS (arm64) | ✅ macOS 13.0+ | ❌ | | macOS (x86_64) | ✅ macOS 13.0+[^1] | ❌ | -| Ubuntu | ⚠️ (WIP) | ✅ 20.04 / 22.04 | -| RHEL | ⚠️ (WIP) | ✅ UBI 9 | - +| Ubuntu | ✅ 20.04+ | ✅ 20.04 / 22.04 | +| RHEL | ✅ Fedora 39[^2], UBI 9 | ✅ UBI 9 | +| Amazon Linux 2 | ✅ Supported | ✅ Supported[^3] | +| Debian 12 | ✅ Supported[^2] | ✅ Supported[^2][^3] | [^1]: Since LLVM project doesn't provide pre-built binaries of `lld` for macOS on x86_64, it will be automatically built from sources by the generator, which will increase its run by at least 15 minutes on recent hardware. You will also need CMake and Ninja preinstalled (e.g. via `brew install cmake ninja`). +[^2]: These distributions are only supported by Swift 5.10.1 and later as both host and target platforms. +[^3]: These versions are technically supported but require custom commands and a Docker container to build the Swift SDK, as the generator will not download dependencies for these distributions automatically. See [issue #138](https://github.com/swiftlang/swift-sdk-generator/issues/138). ## How to use it diff --git a/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift b/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift index beee4b1..88fb7d5 100644 --- a/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift +++ b/Sources/SwiftSDKGenerator/Artifacts/DownloadableArtifacts.swift @@ -51,16 +51,31 @@ struct DownloadableArtifacts: Sendable { self.versions = versions self.paths = paths - 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 hostTriple.os == .linux { + // Amazon Linux 2 is chosen for its best compatibility with all Swift-supported Linux hosts + let linuxArchSuffix = hostTriple.arch == .aarch64 ? "-\(Triple.Arch.aarch64.linuxConventionName)" : "" + self.hostSwift = .init( + remoteURL: versions.swiftDownloadURL( + subdirectory: "amazonlinux2\(linuxArchSuffix)", + platform: "amazonlinux2\(linuxArchSuffix)", + fileExtension: "tar.gz" + ), + localPath: paths.artifactsCachePath + .appending("host_swift_\(versions.swiftVersion)_\(hostTriple.triple).tar.gz"), + 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 + ) + } self.hostLLVM = .init( remoteURL: URL( diff --git a/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Fixup.swift b/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Fixup.swift index fd195b1..4db44f1 100644 --- a/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Fixup.swift +++ b/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Fixup.swift @@ -49,9 +49,13 @@ extension SwiftSDKGenerator { } func symlinkClangHeaders() throws { - try self.createSymlink( - at: self.pathsConfiguration.toolchainDirPath.appending("usr/lib/swift_static/clang"), - pointingTo: "../swift/clang" - ) + let swiftStaticClangPath = self.pathsConfiguration.toolchainDirPath.appending("usr/lib/swift_static/clang") + if !doesFileExist(at: swiftStaticClangPath) { + logGenerationStep("Symlinking clang headers...") + try self.createSymlink( + at: self.pathsConfiguration.toolchainDirPath.appending("usr/lib/swift_static/clang"), + pointingTo: "../swift/clang" + ) + } } } diff --git a/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Unpack.swift b/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Unpack.swift index 5336c6d..0974344 100644 --- a/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Unpack.swift +++ b/Sources/SwiftSDKGenerator/Generator/SwiftSDKGenerator+Unpack.swift @@ -14,7 +14,7 @@ import Helpers import struct SystemPackage.FilePath -let unusedDarwinPlatforms = [ +let unusedTargetPlatforms = [ "appletvos", "appletvsimulator", "embedded", @@ -34,11 +34,13 @@ let unusedHostBinaries = [ "swift-format", "swift-package", "swift-package-collection", + "lldb*", ] let unusedHostLibraries = [ "sourcekitd.framework", "libsourcekitdInProc.so", + "liblldb.so*", ] extension SwiftSDKGenerator { @@ -49,23 +51,32 @@ extension SwiftSDKGenerator { try self.createDirectoryIfNeeded(at: pathsConfiguration.toolchainDirPath) let excludes = - unusedDarwinPlatforms.map { "--exclude usr/lib/swift/\($0)" } + - unusedDarwinPlatforms.map { "--exclude usr/lib/swift_static/\($0)" } + + unusedTargetPlatforms.map { "--exclude usr/lib/swift/\($0)" } + + unusedTargetPlatforms.map { "--exclude usr/lib/swift_static/\($0)" } + unusedHostBinaries.map { "--exclude usr/bin/\($0)" } + unusedHostLibraries.map { "--exclude usr/lib/\($0)" } - try await Shell.run( - #""" - tar -x --to-stdout -f \#(hostSwiftPackagePath) \*.pkg/Payload | - tar -C "\#(pathsConfiguration.toolchainDirPath)" -x \#(excludes.joined(separator: " ")) --include usr - """#, - shouldLogCommands: isVerbose - ) + if hostSwiftPackagePath.string.contains("tar.gz") { + try await Shell.run( + #""" + tar -xzf \#(hostSwiftPackagePath) -C "\#(pathsConfiguration.toolchainDirPath)" -x \#(excludes.joined(separator: " ")) --strip-components=1 + """#, + shouldLogCommands: isVerbose + ) + } else { + try await Shell.run( + #""" + tar -x --to-stdout -f \#(hostSwiftPackagePath) \*.pkg/Payload | + tar -C "\#(pathsConfiguration.toolchainDirPath)" -x \#(excludes.joined(separator: " ")) --include usr + """#, + shouldLogCommands: isVerbose + ) + } } func removeToolchainComponents( _ packagePath: FilePath, - platforms: [String] = unusedDarwinPlatforms, + platforms: [String] = unusedTargetPlatforms, libraries: [String] = unusedHostLibraries, binaries: [String] = unusedHostBinaries ) async throws { diff --git a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift index b8fe5b3..a9f95e6 100644 --- a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift +++ b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/LinuxRecipe.swift @@ -164,7 +164,9 @@ public struct LinuxRecipe: SwiftSDKRecipe { func itemsToDownload(from artifacts: DownloadableArtifacts) -> [DownloadableArtifacts.Item] { var items: [DownloadableArtifacts.Item] = [] - if self.hostSwiftSource != .preinstalled && !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") { + if self.hostSwiftSource != .preinstalled + && self.mainHostTriple.os != .linux + && !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") { items.append(artifacts.hostLLVM) } @@ -279,12 +281,12 @@ public struct LinuxRecipe: SwiftSDKRecipe { try await generator.fixAbsoluteSymlinks(sdkDirPath: sdkDirPath) if self.hostSwiftSource != .preinstalled { - if !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") { + if self.mainHostTriple.os != .linux && !self.versionsConfiguration.swiftVersion.hasPrefix("6.0") { try await generator.prepareLLDLinker(engine, llvmArtifact: downloadableArtifacts.hostLLVM) } if self.versionsConfiguration.swiftVersion.hasPrefix("5.9") || - self.versionsConfiguration.swiftVersion .hasPrefix("5.10") { + self.versionsConfiguration.swiftVersion.hasPrefix("5.10") { try await generator.symlinkClangHeaders() } diff --git a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift index 3385866..e935546 100644 --- a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift +++ b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift @@ -115,7 +115,7 @@ public struct WebAssemblyRecipe: SwiftSDKRecipe { }() try await generator.removeToolchainComponents( pathsConfiguration.toolchainDirPath, - platforms: unusedDarwinPlatforms + ["embedded"], + platforms: unusedTargetPlatforms, libraries: unusedHostLibraries + liblldbNames, binaries: unusedHostBinaries + ["lldb", "lldb-argdumper", "lldb-server"] ) diff --git a/Tests/SwiftSDKGeneratorTests/EndToEndTests.swift b/Tests/SwiftSDKGeneratorTests/EndToEndTests.swift index 49951eb..2026387 100644 --- a/Tests/SwiftSDKGeneratorTests/EndToEndTests.swift +++ b/Tests/SwiftSDKGeneratorTests/EndToEndTests.swift @@ -168,11 +168,17 @@ struct SDKConfiguration { return res } + var hostArch: String? { + let triple = try? SwiftSDKGenerator.getCurrentTriple(isVerbose: false) + return triple?.arch?.rawValue + } + var sdkGeneratorArguments: String { return [ "--sdk-name \(bundleName)", withDocker ? "--with-docker" : nil, "--swift-version \(swiftVersion)-RELEASE", + testLinuxSwiftSDKs ? "--host \(hostArch!)-unknown-linux-gnu" : nil, "--target \(architecture)-unknown-linux-gnu", "--linux-distribution-name \(linuxDistributionName)" ].compactMap{ $0 }.joined(separator: " ") @@ -187,31 +193,81 @@ func skipSlow() throws { ) } +var testLinuxSwiftSDKs: Bool { + ProcessInfo.processInfo.environment.keys.contains("SWIFT_SDK_GENERATOR_TEST_LINUX_SWIFT_SDKS") +} + func buildTestcase(_ logger: Logger, testcase: String, bundleName: String, tempDir: URL) async throws { let testPackageURL = tempDir.appendingPathComponent("swift-sdk-generator-test") let testPackageDir = FilePath(testPackageURL.path) try FileManager.default.createDirectory(atPath: testPackageDir.string, withIntermediateDirectories: true) - logger.info("Creating test project") + logger.info("Creating test project \(testPackageDir)") try await Shell.run("swift package --package-path \(testPackageDir) init --type executable") let main_swift = testPackageURL.appendingPathComponent("Sources/main.swift") try testcase.write(to: main_swift, atomically: true, encoding: .utf8) - logger.info("Building test project") - var buildOutput = try await Shell.readStdout( - "swift build --package-path \(testPackageDir) --experimental-swift-sdk \(bundleName)" - ) - XCTAssertTrue(buildOutput.contains("Build complete!")) - logger.info("Test project built successfully") - - try await Shell.run("rm -rf \(testPackageDir.appending(".build"))") + // This is a workaround for if Swift 6.0 is used as the host toolchain to run the generator. + // We manually set the swift-tools-version to 5.9 to support building our test cases. + logger.info("Updating minimum swift-tools-version in test project...") + let package_swift = testPackageURL.appendingPathComponent("Package.swift") + let text = try String(contentsOf: package_swift, encoding: .utf8) + var lines = text.components(separatedBy: .newlines) + if lines.count > 0 { + lines[0] = "// swift-tools-version: 5.9" + let result = lines.joined(separator: "\r\n") + try result.write(to: package_swift, atomically: true, encoding: .utf8) + } - logger.info("Building test project with static-swift-stdlib") - buildOutput = try await Shell.readStdout( - "swift build --package-path \(testPackageDir) --experimental-swift-sdk \(bundleName) --static-swift-stdlib" - ) - XCTAssertTrue(buildOutput.contains("Build complete!")) - logger.info("Test project built successfully") + var buildOutput = "" + + // If we are testing Linux Swift SDKs, we will run the test cases on a matrix of Docker containers + // that contains each Swift-supported Linux distribution. This way we can validate that each + // distribution is capable of building using the Linux Swift SDK. + if testLinuxSwiftSDKs { + let swiftContainerVersions = ["focal", "jammy", "noble", "fedora39", "rhel-ubi9", "amazonlinux2", "bookworm"] + for containerVersion in swiftContainerVersions { + logger.info("Building test project in 6.0-\(containerVersion) container") + buildOutput = try await Shell.readStdout( + """ + docker run --rm -v \(testPackageDir):/src \ + -v $HOME/.swiftpm/swift-sdks:/root/.swiftpm/swift-sdks \ + --workdir /src swift:6.0-\(containerVersion) \ + /bin/bash -c "swift build --scratch-path /root/.build --experimental-swift-sdk \(bundleName)" + """ + ) + XCTAssertTrue(buildOutput.contains("Build complete!")) + logger.info("Test project built successfully") + + logger.info("Building test project in 6.0-\(containerVersion) container with static-swift-stdlib") + buildOutput = try await Shell.readStdout( + """ + docker run --rm -v \(testPackageDir):/src \ + -v $HOME/.swiftpm/swift-sdks:/root/.swiftpm/swift-sdks \ + --workdir /src swift:6.0-\(containerVersion) \ + /bin/bash -c "swift build --scratch-path /root/.build --experimental-swift-sdk \(bundleName) --static-swift-stdlib" + """ + ) + XCTAssertTrue(buildOutput.contains("Build complete!")) + logger.info("Test project built successfully") + } + } else { + logger.info("Building test project") + buildOutput = try await Shell.readStdout( + "swift build --package-path \(testPackageDir) --experimental-swift-sdk \(bundleName)" + ) + XCTAssertTrue(buildOutput.contains("Build complete!")) + logger.info("Test project built successfully") + + try await Shell.run("rm -rf \(testPackageDir.appending(".build"))") + + logger.info("Building test project with static-swift-stdlib") + buildOutput = try await Shell.readStdout( + "swift build --package-path \(testPackageDir) --experimental-swift-sdk \(bundleName) --static-swift-stdlib" + ) + XCTAssertTrue(buildOutput.contains("Build complete!")) + logger.info("Test project built successfully") + } } func buildTestcases(config: SDKConfiguration) async throws { @@ -241,6 +297,10 @@ func buildTestcases(config: SDKConfiguration) async throws { try await buildTestcase(logger, testcase: testcase, bundleName: bundleName, tempDir: tempDir) } } + + // Cleanup + logger.info("Removing SDK to cleanup...") + try await Shell.run("swift experimental-sdk remove \(bundleName)") } final class Swift59_UbuntuEndToEndTests: XCTestCase { diff --git a/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift b/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift index 1440a92..75f9737 100644 --- a/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift +++ b/Tests/SwiftSDKGeneratorTests/SwiftSDKRecipes/LinuxRecipeTests.swift @@ -16,6 +16,7 @@ import XCTest final class LinuxRecipeTests: XCTestCase { func createRecipe( + hostTriple: Triple = Triple("x86_64-unknown-linux-gnu"), swiftVersion: String = "6.0", withDocker: Bool = false, fromContainerImage: String? = nil, @@ -25,7 +26,7 @@ final class LinuxRecipeTests: XCTestCase { ) throws -> LinuxRecipe { try LinuxRecipe( targetTriple: Triple("aarch64-unknown-linux-gnu"), - hostTriple: Triple("x86_64-unknown-linux-gnu"), + hostTriple: hostTriple, linuxDistribution: .init(name: .ubuntu, version: "22.04"), swiftVersion: swiftVersion, swiftBranch: nil, lldVersion: "", @@ -85,25 +86,51 @@ final class LinuxRecipeTests: XCTestCase { XCTAssert(toolset.linker == nil) } - func testItemsToDownload() throws { - let testCases = [ + func runItemsToDownloadTestCase( + recipe: LinuxRecipe, includesHostLLVM: Bool, includesTargetSwift: Bool, includesHostSwift: Bool + ) throws { + let pathsConfiguration = PathsConfiguration( + sourceRoot: ".", + artifactID: "my-sdk", + targetTriple: recipe.mainTargetTriple + ) + let downloadableArtifacts = try DownloadableArtifacts( + hostTriple: recipe.mainHostTriple, + targetTriple: recipe.mainTargetTriple, + recipe.versionsConfiguration, + pathsConfiguration + ) + let itemsToDownload = recipe.itemsToDownload(from: downloadableArtifacts) + let foundHostLLVM = itemsToDownload.contains(where: { $0.remoteURL == downloadableArtifacts.hostLLVM.remoteURL }) + let foundTargetSwift = itemsToDownload.contains(where: { $0.remoteURL == downloadableArtifacts.targetSwift.remoteURL }) + let foundHostSwift = itemsToDownload.contains(where: { $0.remoteURL == downloadableArtifacts.hostSwift.remoteURL }) + + // If this is a Linux host, we do not download LLVM + XCTAssertEqual(foundHostLLVM, includesHostLLVM) + XCTAssertEqual(foundTargetSwift, includesTargetSwift) + XCTAssertEqual(foundHostSwift, includesHostSwift) + } + + func testItemsToDownloadForMacOSHost() throws { + let hostTriple = Triple("x86_64-apple-macos") + let testCases: [(recipe: LinuxRecipe, includesHostLLVM: Bool, includesTargetSwift: Bool, includesHostSwift: Bool)] = [ ( // Remote tarballs on Swift < 6.0 - recipe: try createRecipe(swiftVersion: "5.10"), + recipe: try createRecipe(hostTriple: hostTriple, swiftVersion: "5.10"), includesHostLLVM: true, includesTargetSwift: true, includesHostSwift: true ), ( // Remote tarballs on Swift >= 6.0 - recipe: try createRecipe(swiftVersion: "6.0"), + recipe: try createRecipe(hostTriple: hostTriple, swiftVersion: "6.0"), includesHostLLVM: false, includesTargetSwift: true, includesHostSwift: true ), ( // Remote target tarball with preinstalled toolchain - recipe: try createRecipe(swiftVersion: "5.9", includeHostToolchain: false), + recipe: try createRecipe(hostTriple: hostTriple, swiftVersion: "5.9", includeHostToolchain: false), includesHostLLVM: false, includesTargetSwift: true, includesHostSwift: false @@ -111,6 +138,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Local packages with Swift < 6.0 recipe: try createRecipe( + hostTriple: hostTriple, swiftVersion: "5.10", hostSwiftPackagePath: "/path/to/host/swift", targetSwiftPackagePath: "/path/to/target/swift" @@ -122,6 +150,7 @@ final class LinuxRecipeTests: XCTestCase { ( // Local packages with Swift >= 6.0 recipe: try createRecipe( + hostTriple: hostTriple, swiftVersion: "6.0", hostSwiftPackagePath: "/path/to/host/swift", targetSwiftPackagePath: "/path/to/target/swift" @@ -133,25 +162,67 @@ final class LinuxRecipeTests: XCTestCase { ] for testCase in testCases { - let pathsConfiguration = PathsConfiguration( - sourceRoot: ".", - artifactID: "my-sdk", - targetTriple: testCase.recipe.mainTargetTriple + try runItemsToDownloadTestCase( + recipe: testCase.recipe, + includesHostLLVM: testCase.includesHostLLVM, + includesTargetSwift: testCase.includesTargetSwift, + includesHostSwift: testCase.includesHostSwift ) - let downloadableArtifacts = try DownloadableArtifacts( - hostTriple: testCase.recipe.mainHostTriple, - targetTriple: testCase.recipe.mainTargetTriple, - testCase.recipe.versionsConfiguration, - pathsConfiguration + } + } + + func testItemsToDownloadForLinuxHost() throws { + let hostTriple = Triple("x86_64-unknown-linux-gnu") + let testCases = [ + ( + // Remote tarballs on Swift < 6.0 + recipe: try createRecipe(hostTriple: hostTriple, swiftVersion: "5.10"), + includesTargetSwift: true, + includesHostSwift: true + ), + ( + // Remote tarballs on Swift >= 6.0 + recipe: try createRecipe(hostTriple: hostTriple, swiftVersion: "6.0"), + includesTargetSwift: true, + includesHostSwift: true + ), + ( + // Remote target tarball with preinstalled toolchain + recipe: try createRecipe(hostTriple: hostTriple, swiftVersion: "5.9", includeHostToolchain: false), + includesTargetSwift: true, + includesHostSwift: false + ), + ( + // Local packages with Swift < 6.0 + recipe: try createRecipe( + hostTriple: hostTriple, + swiftVersion: "5.10", + hostSwiftPackagePath: "/path/to/host/swift", + targetSwiftPackagePath: "/path/to/target/swift" + ), + includesTargetSwift: false, + includesHostSwift: false + ), + ( + // Local packages with Swift >= 6.0 + recipe: try createRecipe( + hostTriple: hostTriple, + swiftVersion: "6.0", + hostSwiftPackagePath: "/path/to/host/swift", + targetSwiftPackagePath: "/path/to/target/swift" + ), + includesTargetSwift: false, + includesHostSwift: false ) - let itemsToDownload = testCase.recipe.itemsToDownload(from: downloadableArtifacts) - let foundHostLLVM = itemsToDownload.contains(where: { $0.remoteURL == downloadableArtifacts.hostLLVM.remoteURL }) - let foundTargetSwift = itemsToDownload.contains(where: { $0.remoteURL == downloadableArtifacts.targetSwift.remoteURL }) - let foundHostSwift = itemsToDownload.contains(where: { $0.remoteURL == downloadableArtifacts.hostSwift.remoteURL }) + ] - XCTAssertEqual(foundHostLLVM, testCase.includesHostLLVM) - XCTAssertEqual(foundTargetSwift, testCase.includesTargetSwift) - XCTAssertEqual(foundHostSwift, testCase.includesHostSwift) + for testCase in testCases { + try runItemsToDownloadTestCase( + recipe: testCase.recipe, + includesHostLLVM: false, // when host is Linux we do not download LLVM + includesTargetSwift: testCase.includesTargetSwift, + includesHostSwift: testCase.includesHostSwift + ) } }