Hey,
I am trying to compile a Swift package for wasm as a library for the godot engine, which exposes its api through a C header. To include that header I had to create an empty C language target, containing an ugh.c file with no code in it. Otherwise Swift refuses to see this .target() as a module and I don't get the headers, for whatever reason.
Everything works perfectly fine on macOS, I can access the dylib within godot, create a godot_string instance and print "Hello world!", from Swift.
I also want this to work with wasm, unfortunately, it fails to compile with: No available targets are compatible with triple "wasm32-emscripten-wasi" which I assume is because of the C language target?
How can I compile to a wasm library?
> swift build -c release --triple wasm32-unknown-wasi
Building for production...
error: unable to create target: 'No available targets are compatible with triple "wasm32-unknown-wasi"'
1 error generated.
[0/2] Compiling GodotApi ugh.c
>
But if that's true and that target is not working then (most likely) it's no use trying at all; godot uses emscripten and the Rust community spent a while to even get it working with the language properly, it's very annoying and you need to build the engine and library with the same version too, because nothing is exactly stable yet.
If I were to get rid of the standard library completely and so the large String dependencies, I assume it would be much easier to just build for whatever platform I want?
Godot already has it's own class/type system, including strings, so it makes sense to write a tiny Swift std module that just reimplements everything with godot, so for example string literals would create godot strings
There is absolutely no point in bringing in Swift types increasing binary size, if they are not going to be used.
Also, I only need the header, the types, the function pointers. not the "ugh.c" file. Can I maybe take the generated Swift interface to avoid the empty C dependency (which is probably why it can't compile)
Are you using a SwiftWasm toolchain or a toolchain from swift.org? The latter doesn't support Wasm either.
I don't think so. There's a significant amount of work to be done for each platform in the runtime, the toolchain itself, and also its build system. "Getting rid of the standard library" won't help, but actually could complicate things, since you need numerics, pointers etc on any platform. Reimplementing those from scratch you'll end up with something very close to stdlib APIs anyway, unless you're ready to redesign those on your own.
That's not the reason for why it can't be compiled. C targets are required to have at least a single source file (even an empty one) by the build system.
I am aware of that, and I've read the source code of uSwift and some of the official standard library, it's not that bad. godot already has most of the complicated parts implemented and exposed through the api, so for types like String I would just wrap godot_string
This can be done with the standard library still present, but then I have an unnecessary String dependency
You're most likely not specifying a full path to the toolchain. The SwiftWasm toolchain does support wasm32-unknown-wasi triple, in fact that's one of its few differences from the upstream toolchain. If you've installed it on macOS, you can target Wasm32/WASI like this:
Well, unfortunately (as expected) godot does not understand the library. I need to build using the exact same version of emscripten.
I'm using -emit-bc and trying to compile with emcc. It's complaining about missing symbols such as: wasm-ld: error: build/libswift.bc: undefined symbol: $sytWV
As far as I know that's because I don't have the runtime.
Can I force swiftc to -emit-bc for wasm32-unknown-emscripten without recompiling the toolchain I'm using the wasi target and I assume that could cause issues.
Why is this still a limitation when I don't have the standard library, I don't depend on anything :/
$sytWV is the value witness table for an empty tuple (you can find this out from swift-demangle), normally provided by the Swift runtime. For better or worse—and in your case “for worse”—Swift is a very dynamic language with a runtime you can’t just ignore except in cases where all generics, existentials, class allocations, and capturing closures are optimized away. Even without the standard library, the compiler wants the runtime to be present.
I can live without classes but I do like generics, I will have to implement it at some point but first I would like to at least get it to work at all.
It would be interesting to implement the runtime in Swift.
Oh! It makes sense, I have defined typealias Void = ()
Looking at uSwift, it seems like you can compile a runtime and link it statically
Yeah, the runtime doesn’t have to be pre-linked into the standard library, that’s just convenient for Swift’s supported platforms.
If you really want to go down this route, you may be interested in my hobby project porting Swift to Mac OS 9. It is a very large amount of work, but you can have an alternate implementation of the Swift runtime that only supports a subset of functionality of the real runtime, and most of it (but not all) can be written in Swift if you’re careful.
I’m not sure I recommend this for a production project, though, over working with the existing uSwift and SwiftWasm projects to add emscripten-wasm as a supported variant.
I could try using uSwift, but I'm still trying to build the unknown target toolchain.
It compiles, but fails some tests and that seems to prevent it from finishing the toolchain. I can't find a way to tell build-toolchain to skip tests.
I'm not even sure the failing tests are related to swift, there's a lot of Python and lldb before the error happens. Or maybe it finished some tests and now is trying to build lldb. There's a lot of C++ in the output which is not a language I know very well