Hello lovely community,
I just pushed an Embedded Swift proof-of-concept Wasm app out the door that uses
- JavaScriptKit
- elementary-dom (the experimental reactive Elementary package I am playing with)
- SwiftPM for building the whole thing (with a few hacks, see below)
It is a simplified wordle clone that clocks in at around 71 kB (compressed wasm).
Check it out here ->> Swiftle - Embedded Demo App <<- (source code)
Things with this setup are a bit rough but almost good enough, and I wanted to share a "mission status report" with a few thoughts I had along the way:
SwiftPM - Emit Empty Object File
I understand that building an embedded binary is not exactly "officially supported" right now, but things are very close to good enough, so I hope I can provide some motivation to close the few remaining gaps eventually.
This post by @rauhul describes it well
but to me the one issue that stands out is -Xfrontend -emit-empty-object-file
. All the other things can be solved today by throwing a bunch of flags at swift build
, but this one needs to be placed on all swift targets but the main one.
I ended up adding an environment variable-based conditional .unsafeFlags
swift setting in all Package.swift
files. This a) does not scale, and b) clashes with the SwiftPM rule to not allow unsafe flags from versioned package tags. At the moment all dependencies must reference branches. Not sure if there is a better work-around, but this is the biggest obstacle atm. (Also, this means that package traits would not really help here as well).
SwiftPM - Resources
IIUC SwiftPM generates a bit of Foundation
-based bundle access code if you have resources defined in your package. That's nice and all, but a bit annoying if there is no Foundation
. It would be nice to have an option to copy the files in a bundle folder, but skip the codegen.
SwiftPM - Conditional Target Dependencies
Maybe this is possible already, but I could not figure out how to specify a platform condition on a target dependency to mean "wasm32-none" or similar.
.executableTarget(
name: "EmbeddedApp",
dependencies: [
.product(name: "ElementaryDOM", package: "ElementaryDOM"),
.product(name: "JavaScriptKit", package: "JavaScriptKit"),
.product(
name: "dlmalloc", // I only need this for runtimeless wasm
package: "swift-dlmalloc",
condition: .when(platforms: [.custom("what do I write here?")]))
]
),
Missing @_expose(wasm)
symbols
Similar to the issue of cdecls
not working in dependencies, I also could not get @_expose(wasm)
to work without tricks. I understand that these symbols are "shaken" out if not used (which seems reasonable), so a hope was that @_used
would do the trick - but that also does not work.
If I reference the exposed function (not even call it) in the main module, things work (so the "exposedness" is preserved, but it needs to be referenced somehow.)
Not sure how much of this is intended or even defined behavior, so I ask: Should an unreferenced @_used @_expose(...)
function be present as a wasm export in the final binary?
Strings - Equality
Swift's String/Unicode situation has been discussed many a time before and I totally understand why things are the way they are. Long story short, I ended up adding a String.utf8Equals
in basically every package and replaced all ==
comparisons with it.
I know, I know, but I can imagine this topic will be one of the first for many to stumble over.
So, I wonder if there is some imaginable opt-in raw UTF8 mode for Embedded to say "I am ok with UTF8-comparisons" or something like this? Not sure about sorting and other string tricks, but equating and hashing would be sweet.
SwiftPM - Linking optional extras
As I understand the unicode support stuff can be opted-in to by linking a provided .a file. Is there an easy way to add this to a SwiftPM setup in a portable way?
I did not try the unicode archive, but I failed with a quick experiment of linking wasi-libc stuff manually.
Variadic generics
Their status is documented as "not yet"... sure would be ever so sweet to have these available ; )
Observation for Embedded?
As other, deeper parts of the stdlib (like concurrency features) are ported for embedded I wonder if there are thoughts on having (at least parts of) Observation
available anytime soon?
Whew, sorry for the wall of text. I hope this summary from the Embedded Wasm for Web perspective can be of some value.