From ed98965512984a5c2ed8acf802aa46fccbbbb9c1 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Thu, 11 Sep 2025 07:39:01 -0700 Subject: [PATCH] Make targetSwiftPackagePath optional for WASM SDK generation This allows generating WASM SDKs that do not have support for targeting Swift. --- Sources/GeneratorCLI/GeneratorCLI.swift | 5 +- .../SwiftSDKRecipes/WebAssemblyRecipe.swift | 131 +++++++++--------- 2 files changed, 69 insertions(+), 67 deletions(-) diff --git a/Sources/GeneratorCLI/GeneratorCLI.swift b/Sources/GeneratorCLI/GeneratorCLI.swift index a332799..32400a4 100644 --- a/Sources/GeneratorCLI/GeneratorCLI.swift +++ b/Sources/GeneratorCLI/GeneratorCLI.swift @@ -420,15 +420,12 @@ extension GeneratorCLI { } func run() async throws { - guard let targetSwiftPackagePath = generatorOptions.targetSwiftPackagePath else { - throw StringError("Missing expected argument '--target-swift-package-path'") - } let recipe = try WebAssemblyRecipe( hostSwiftPackage: generatorOptions.hostSwiftPackagePath.map { let hostTriples = try self.generatorOptions.deriveHostTriples() return WebAssemblyRecipe.HostToolchainPackage(path: FilePath($0), triples: hostTriples) }, - targetSwiftPackagePath: FilePath(targetSwiftPackagePath), + targetSwiftPackagePath: generatorOptions.targetSwiftPackagePath.map { FilePath($0) }, wasiSysroot: FilePath(self.wasiSysroot), swiftVersion: self.generatorOptions.swiftVersion, logger: loggerWithLevel(from: self.generatorOptions) diff --git a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift index 5525aea..2532154 100644 --- a/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift +++ b/Sources/SwiftSDKGenerator/SwiftSDKRecipes/WebAssemblyRecipe.swift @@ -17,7 +17,9 @@ import struct SystemPackage.FilePath package struct WebAssemblyRecipe: SwiftSDKRecipe { let hostSwiftPackage: HostToolchainPackage? - let targetSwiftPackagePath: FilePath + + /// Optional to allow creating WebAssembly Swift SDKs that don't include Swift support and therefore can only target C/C++. + let targetSwiftPackagePath: FilePath? let wasiSysroot: FilePath let swiftVersion: String package let logger: Logger @@ -34,7 +36,7 @@ package struct WebAssemblyRecipe: SwiftSDKRecipe { package init( hostSwiftPackage: HostToolchainPackage?, - targetSwiftPackagePath: FilePath, + targetSwiftPackagePath: FilePath?, wasiSysroot: FilePath, swiftVersion: String, logger: Logger @@ -47,7 +49,10 @@ package struct WebAssemblyRecipe: SwiftSDKRecipe { } package var defaultArtifactID: String { - "\(self.swiftVersion)_wasm" + if hostSwiftPackage == nil && targetSwiftPackagePath == nil { + return "wasm" + } + return "\(self.swiftVersion)_wasm" } package let shouldSupportEmbeddedSwift = true @@ -134,74 +139,74 @@ package struct WebAssemblyRecipe: SwiftSDKRecipe { httpClient: some HTTPClientProtocol ) async throws -> SwiftSDKProduct { let pathsConfiguration = generator.pathsConfiguration - let targetSwiftLibPath = self.targetSwiftPackagePath.appending("usr/lib") - - logger.info("Copying Swift binaries for the host triple...") var hostTriples: [Triple]? = nil - if let hostSwiftPackage { - hostTriples = hostSwiftPackage.triples - try await generator.rsync( - from: hostSwiftPackage.path.appending("usr"), - to: pathsConfiguration.toolchainDirPath - ) + if let targetSwiftLibPath = self.targetSwiftPackagePath?.appending("usr/lib") { + logger.info("Copying Swift binaries for the host triple...") + if let hostSwiftPackage { + hostTriples = hostSwiftPackage.triples + try await generator.rsync( + from: hostSwiftPackage.path.appending("usr"), + to: pathsConfiguration.toolchainDirPath + ) + + logger.info("Removing unused toolchain components...") + let liblldbNames: [String] = try await { + let libDirPath = pathsConfiguration.toolchainDirPath.appending("usr/lib") + guard await generator.doesFileExist(at: libDirPath) else { + return [] + } + return try await generator.contentsOfDirectory(at: libDirPath).filter { dirEntry in + // liblldb is version suffixed: liblldb.so.17.0.0 + dirEntry.hasPrefix("liblldb") + } + }() + try await generator.removeToolchainComponents( + pathsConfiguration.toolchainDirPath, + platforms: unusedTargetPlatforms, + libraries: unusedHostLibraries + liblldbNames, + binaries: unusedHostBinaries + ["lldb", "lldb-argdumper", "lldb-server"] + ) + // Merge target Swift package with the host package. + try await self.mergeTargetSwift(from: targetSwiftLibPath, generator: generator) + } else { + // Simply copy the target Swift package into the Swift SDK bundle when building host-agnostic Swift SDK. + try await generator.createDirectoryIfNeeded( + at: pathsConfiguration.toolchainDirPath.appending("usr") + ) + try await generator.copy( + from: targetSwiftLibPath, + to: pathsConfiguration.toolchainDirPath.appending("usr/lib") + ) + } - logger.info("Removing unused toolchain components...") - let liblldbNames: [String] = try await { - let libDirPath = pathsConfiguration.toolchainDirPath.appending("usr/lib") - guard await generator.doesFileExist(at: libDirPath) else { - return [] - } - return try await generator.contentsOfDirectory(at: libDirPath).filter { dirEntry in - // liblldb is version suffixed: liblldb.so.17.0.0 - dirEntry.hasPrefix("liblldb") - } - }() - try await generator.removeToolchainComponents( - pathsConfiguration.toolchainDirPath, - platforms: unusedTargetPlatforms, - libraries: unusedHostLibraries + liblldbNames, - binaries: unusedHostBinaries + ["lldb", "lldb-argdumper", "lldb-server"] - ) - // Merge target Swift package with the host package. - try await self.mergeTargetSwift(from: targetSwiftLibPath, generator: generator) - } else { - // Simply copy the target Swift package into the SDK bundle when building host-agnostic SDK. - try await generator.createDirectoryIfNeeded( - at: pathsConfiguration.toolchainDirPath.appending("usr") + let autolinkExtractPath = pathsConfiguration.toolchainBinDirPath.appending( + "swift-autolink-extract" ) - try await generator.copy( - from: targetSwiftLibPath, - to: pathsConfiguration.toolchainDirPath.appending("usr/lib") - ) - } - let autolinkExtractPath = pathsConfiguration.toolchainBinDirPath.appending( - "swift-autolink-extract" - ) - - // WebAssembly object file requires `swift-autolink-extract` - if await !generator.doesFileExist(at: autolinkExtractPath), - await generator.doesFileExist( - at: generator.pathsConfiguration.toolchainBinDirPath.appending("swift") - ) - { - logger.info("Fixing `swift-autolink-extract` symlink...") - try await generator.createSymlink(at: autolinkExtractPath, pointingTo: "swift") - } + // WebAssembly object file requires `swift-autolink-extract` + if await !generator.doesFileExist(at: autolinkExtractPath), + await generator.doesFileExist( + at: generator.pathsConfiguration.toolchainBinDirPath.appending("swift") + ) + { + logger.info("Fixing `swift-autolink-extract` symlink...") + try await generator.createSymlink(at: autolinkExtractPath, pointingTo: "swift") + } - // TODO: Remove this once we drop support for Swift 6.2 - // Embedded Swift looks up clang compiler-rt in a different path. - let embeddedCompilerRTPath = pathsConfiguration.toolchainDirPath.appending( - "usr/lib/swift/clang/lib/wasip1" - ) - if await !generator.doesFileExist(at: embeddedCompilerRTPath) { - try await generator.createSymlink( - at: embeddedCompilerRTPath, - pointingTo: "../../../swift_static/clang/lib/wasi" + // TODO: Remove this once we drop support for Swift 6.2 + // Embedded Swift looks up clang compiler-rt in a different path. + let embeddedCompilerRTPath = pathsConfiguration.toolchainDirPath.appending( + "usr/lib/swift/clang/lib/wasip1" ) + if await !generator.doesFileExist(at: embeddedCompilerRTPath) { + try await generator.createSymlink( + at: embeddedCompilerRTPath, + pointingTo: "../../../swift_static/clang/lib/wasi" + ) + } } - // Copy the WASI sysroot into the SDK bundle. + // Copy the WASI sysroot into the Swift SDK bundle. let sdkDirPath = pathsConfiguration.swiftSDKRootPath.appending("WASI.sdk") try await generator.rsyncContents(from: self.wasiSysroot, to: sdkDirPath)