(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.).
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)
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?
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:
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
The error occurs while it is trying to lead the manifest, so I think it is the host’sFoundation 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.
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
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.
This crash is expected behavior because clang doesn't allow non-prototyped function definition without varargs. (But I know we should diagnose before crash )
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.
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.