Build Swift app to WebAssembly using SwiftPM

Hi,

I'm trying to build my Swift project to WebAssembly without WASI (app will run in browser on client side). Building single file works great (took example from Some feedback from my short experience with SwiftWasm - #5 by Max_Desiatov):

swiftc -Osize -Xcc -fdeclspec -target wasm32-unknown-none-wasm -enable-experimental-feature Extern -enable-experimental-feature Embedded -wmo Sources/main.swift -c -o main.o
/opt/homebrew/opt/lld/bin/wasm-ld --no-entry main.o -o main.wasm

But when I'm trying to do it using swift build :

swift build --triple wasm32-unknown-none-wasm --product app -c release -Xswiftc -enable-experimental-feature -Xswiftc Extern -Xswiftc -enable-experimental-feature -Xswiftc Embedded -Xswiftc -Xcc -Xswiftc -fdeclspec

with Package.swift:

import PackageDescription

let package = Package(
  name: "app",
  products: [
    .executable(name: "app", targets: ["app"])
  ],
  targets: [
    .executableTarget(name: "app"),
  ]
)

it throws an error:

error: link command failed with exit code 1 (use -v to see invocation)
wasm-ld: error: cannot open crt1.o: No such file or directory
wasm-ld: error: unable to find library -lc
wasm-ld: error: cannot open /Users/user/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2025-06-12-a.xctoolchain/usr/lib/clang/17/lib/wasm32-unknown-none-wasm/libclang_rt.builtins.a: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)

So for some reason builder adds to the linker command this parameters:

   crt1.o \
   -lc /Users/user/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2025-06-12-a.xctoolchain/usr/lib/clang/17/lib/wasm32-unknown-none-wasm/libclang_rt.builtins.a \

They are not required for successful linking. Is it possible somehow to tell SwiftPM to remove it from linking process?

The toolchain itself does not include compiler-rt for Wasm, but it's included in the Swift SDK for Wasm instead.
I recommend to use swift-<version>_wasm-embedded variant Swift.org - Getting Started with Swift SDKs for WebAssembly
If you really don't want to use Swift SDK, you can pass linkerSettings: [.unsafeFlags(["-Xclang-linker", "-nodefaultlibs"]), but note that you will lose a lot of functionalities.

3 Likes

Thank you for your reply. I'd prefer to use Swift SDK, but when I'm building using wasm-embedded SDK it'd builds with WASI. Build command:

swift build --swift-sdk swift-6.2-DEVELOPMENT-SNAPSHOT-2025-06-17-a_wasm-embedded --product app -c release -Xswiftc -enable-experimental-feature -Xswiftc Extern -Xswiftc -enable-experimental-feature -Xswiftc Embedded -Xswiftc -Xcc -Xswiftc -fdeclspec

Do I need to specify exact triple for building without WASI? Like I did it previously with -target wasm32-unknown-none-wasm ?

No, you don't need to specify any of those options with the Embedded Swift SDK. --swift-sdk is enough, -c release may be still required with 6.2 snapshots, but not with main snapshots where debug builds are now possible.

Thus with the main snapshots of the toolchain, this is the whole command for debug build:

swift build --swift-sdk swift-DEVELOPMENT-SNAPSHOT-2025-06-17-a_wasm-embedded

and nothing else is needed, unless you build a specific product with --product.

This is not something I would recommend at this point, as WASI-libc provides you an allocator, RNG, basic I/O facilities, and much more, most importantly compatibility with many existing libraries and packages. The binary size is still quite small (10 kB for print("Hello, World!")), and you get a stable imports ABI that almost all Wasm runtimes support or have shims for.

What's your use case for building without WASI?

FYI: Some tools provide a way to replace WASI syscalls with stub implementations. GitHub - near/wasi-stub: This tool takes a wasm file, replace all wasi_snapshot_preview1 import to (stub) functions defines in the same module. This is useful when executing wasm in sandbox enviroment where wasi is not available.

1 Like

Yes, but it still doesn't work on the NEAR blockchain. I compile the WebAssembly (WASM) file, stub the WASI imports, and disable all WASM features, but I still encounter errors when calling the function on-chain. So far, I've only had success with WASM files compiled using the wasm32-unknown-unknown target. Every language that supports this target allows me to upload the code to the blockchain and call functions. However, with languages that use the wasm32-unknown-wasi target, I haven’t been able to get it working for some reason.

1 Like

But I also want to mention that compiling Swift code to WebAssembly was a great experience for me.

1 Like

vlmoon99/near-sdk-swift: Experimental Near SDK for Swift lang
I built and deployed it on the chain, and it works well. I believe this can be very useful in the future for developers who want to write smart contracts in Swift and communicate with the blockchain using Swift and WebAssembly. Thanks to everyone who made this possible!