WebAssembly + SwiftPM

(This is mostly a question for @kateinoigakukun, but I thought I’d ask publicly for the many eavesdroppers that will come by wondering the same thing.)

I saw the recent PR adding WebAssembly as a declarable platform in SwiftPM manifests. I’m curious how close it is to being usable. Is that the first of a long series of additions? Or does the existing cross‐compilation support mean it should pretty much already work?

A few months ago I set out I set out to set up package testing on Android and Windows. I considered WebAssembly at the time too, but from what I could gather then, it appeared it was not even possible to link multiple modules together yet. But if it is now approaching usability with SwiftPM, I would be very curious to know how one would go about building a package (i.e. where to get or how to build toolchains and SDKs, what kinds of extra flags and patches are necessary, etc.).

1 Like

SwiftPM with WebAssembly works well with that patch.

I already used SwiftPM to build a Swift project which is targeting for wasm32-unknown-wasi GitHub - swiftwasm/JavaScriptKit: Swift framework to interact with JavaScript through WebAssembly.

WebAssembly doesn't support linking multiple modules at runtime but wasm-ld which is a relocatable object file linker can link multiple modules at build time.

Now, Swift for WebAseembly depends on WASI and wasi-sysroot as SDK, but it's not installed in fixed absolute path, so users need to pass --sysroot flag when building.
In addition, when exporting or importing symbols with host environment, users need to pass additional flags to allow undefined symbol at link time and to export specific symbols.
(e.g. https://github.com/kateinoigakukun/JavaScriptKit/blob/master/script/build-package.sh)

FYI: Wasm Support - #14 by kateinoigakukun

7 Likes

That’s great news! If there are ways we can continue to improve SwiftPM to make WebAssembly use easier please let us know... what are other systems doing here? Would it ever make sense for SwiftPM to download the toolchain/SDK automatically and manage its location, for example?

1 Like

I'm planning to embed WASI sysroot in Swift toolchain and pass those sysroot flag as default when targeting WebAssembly.

2 Likes

Okay, I started setting it up and managed to get a heavily stripped‐down package to build. Foundation and Dispatch didn’t work, but that wasn’t much of a surprise at this early stage.

Two issues that did surprise me were:

  1. The Linux toolchain doesn’t seem to work. (macOS did.)

    $ swift build --triple wasm32-unknown-wasi
    /usr/bin/swift-build: error while loading shared libraries: libFoundation.so: cannot open shared object file: No such file or directory
    

    (Full context here.)

    The error occurs while it is trying to lead the manifest, so I think it is the host’s Foundation that is expected but missing. I tried installing a standard toolchain at /, (and then using the WASI toolchain installed elsewhere) but it didn’t help. I imagine it only works on macOS because Foundation is part of the operating system. There might be problems ahead if at some point the toolchain expects a bundled version newer than the system has.

  2. It crashed when I attempted to use an imported C function.

    $ .build/SDG/Swift/usr/bin/swift build --triple wasm32-unknown-wasi
    [1/6] Compiling WSCrossPlatformC CrossPlatform.c
    <unknown>:0: error: fatal error encountered during compilation; please file a bug report with your project and the crash log
    <unknown>:0: note: Functions with 'no-prototype' attribute must take varargs: helloC
    

    (Full context and stack trace here.)

But I must say, this is vastly simpler to install and use than the comparable Android and Windows toolchains. Apparently I had it backwards when I decided to start easy and try the others first. Well done!

It would be nice to create a kind of “swift SDK” spec - I’m thinking basically a directory with a file specifying default compiler options and containing (or symlinking to) whatever files or tools it needs.

Perhaps we can then offer a built-in command to easily download and install SDKs so people can share cross-compiling toolchains.

The long commands full of various paths and flags you need when cross-compiling can get kind of annoying.

I mean, even having to write the full triple is a bit ugly. It would be nicer to just say swift build -target wasi32, where “wasi32” could be the name of the SDK.

1 Like

Thanks for investigation!

Sorry, I forgot to set rpath for swift-build to find dynamic libraries relative to itself path. I fixed this issue in this PR [WASM] Pass -rpath flag to find dynamic library from relative to it's executable path by kateinoigakukun · Pull Request #374 · swiftwasm/swift · GitHub

This crash is expected behavior because clang doesn't allow non-prototyped function definition without varargs. (But I know we should diagnose before crash :sweat_smile: )

After adding explicit void parameter to indicate that the helloC doesn't take any argument, building the target will be succeeded.

This explicit prototype declaration is necessary because WebAssembly requires that callee and caller signatures are same.

3 Likes

I think @compnerd from the core team has been working on that.

My personal opinion is that in the long run SwiftPM should be able to simply do swift build --platform android. (--target already means something else.) At that point SwiftPM would check standard install locations for matching SDKs and build each architecture for which you’ve installed an SDK. This would essentially mirror what xcodebuild does with iOS.

I don’t know if the SDK arrangement is ready for that though, because right now if you unzip multiple architectures’ SDKs to /, it looks to me like they would stomp on each other’s files, since they share the same SDK name right now. I think the goal in the end was to have a single multi‐architecture SDK, (like iOS), but it doesn’t look like that will be a reality for a while.

In the meantime I have been adding some of the flags to SwiftPM so that fewer of them need to be supplied manually each time.

@ddunbar’s idea of having SwiftPM (or some other tool) manage SDK downloads and updates could be interesting, but the first step is to get them actually working cleanly. Not much sense having a managed download if you still have to manually look up the extra flags.

2 Likes