PoC: Improving macro build times with WebAssembly

This! If swift-syntax takes 12 minutes to build on Xcode Cloud and Wasm Macros bring that down to 0, I think it's worth a number of concessions. And sure there are other ways to achieve this (improving SwiftPM caching, switching to Bazel, etc etc) but while many of these are ideals to aspire to, Wasm macros solve this problem today.

I can't speak to Apple's plans but the WASI sdk is ~130 MB, and relative to the Swift toolchain (already several GB in size) I think this is definitely worth it. And I'm sure there's ways to go about this that don't mandate installing a WASI sdk — it could definitely be an optional addon rather than something that's required. Alternatively, macro authors could build for their host during local dev, and build for WASI on CI when publishing the macro as a package. I agree that there are valid concerns to keep in mind when solving this problem, but I do think they can all be solved.


The macro author might need to install a Swift SDK for WASI only if they want to publish a macro built for WASI. You as a macro user don't need to do that. If theoretically someone finds a way to build macros in the embedded mode with no WASI dependencies, no Swift SDK installation would be required whatsoever, Embedded Swift for Wasm is available out of the box in recent development snapshots off main.

The toolchain part is also not correct, all recent development snapshots support code generation for Wasm already out of the box with no additional installation steps required.

I don't think that's ever been proposed, especially as something to be rolled out right now. We're at a PoC stage, as the title of this topic indicates.

That may be true for some particularly old distributions, recent Swift SDKs for WASI have not exceeded 70 MB.


To elaborate on this, IMO it makes sense to come up with a Swift SDK for WASI that doesn't contain prebuilt swift-corelibs-foundation and swift-corelibs-xctest, either of which are unlikely to be needed in a macro anyway. And then if they are needed, they can be added as package dependencies instead. That should allow us to shrink such Swift SDK bundle even more, hopefully to only a few dozen MB.

@kateinoigakukun WDYT?

For context I got to this number by adding lib/swift_static/wasi (90 MB) and wasm-ld (40 MB) (appears to be missing from some newer SDKs but afaict still needed for linking, unless lld is now shipped OOTB?)

Also I'm not counting a handful of other components that seem like they could be pruned:

  • lib/swift{,_static}/clang/lib/linux
  • perhaps the C++ STL, if we can pull that from the base toolchain?

I see now that you were referring to compressed size — indeed sounds like that can be shrunk down further than 70 mb if we remove these bits, even if we're stuck with deflate compression.

Yes, lld is now included in latest development snapshots.

Good shout, I'm not sure why that one in particular would be needed, and it's ~52 MiB uncompressed.

I think the summary is that it's quite realistic to shrink it to negligible size when compared to the total size of an average Swift distribution on any platform.

1 Like

although i have not used it myself, my understanding is the way people are currently distributing binary dependencies is by checking them in with the git repo, e.g. how InstantSyntax does it.

this is okay if the package exists specifically to vend a precompiled version of another package, but if packages themselves start checking in precompiled macros to git repos, that will be very, very bad for SwiftPM performance, because SwiftPM only knows how to perform a deep clone of package dependencies, which makes it sensitive to the size of the git repo history.

building WASI on CI doesn’t make much sense under this model because the CI would have to commit changes back to the git repo and skip the next CI run.

1 Like

There’s another binaryTarget overload that takes an arbitrary URL, see for example how Google Maps does it:

This should mitigate the need to check in binaries and avoid bottlenecking SwiftPM.


okay, i have not had much experience with binary dependencies (as they are macOS only) so i did not know that existed.

of course i now realize that means none of this will benefit Linux users unless SwiftPM starts supporting binary dependencies on Linux. there seem to be some hard blockers for that in general due to lack of ABI stability, but i imagine this is less of an issue for WASI. should that decision be revisited?


Fortunately we don’t need a stable Swift ABI for binary macros. Macros are executables that “communicate” with the outside world through a JSON-based interface over standard input+output, so as long as we can run wasm binaries on Linux and Windows (we can with WasmKit) we’re good.


We side-step this with WASI, as everything targeting it is statically linked into a single binary, at least with WASI 0.1. Subsequent versions of WASI define a Canonical ABI, which makes a lot of things easier. This doesn't mean one would automatically get binary target support for other platforms without Swift ABI stability but with dynamic linking. That issue remains unresolved and is orthogonal to the current discussion.


This may be going even further off-topic but it feels like everyone is trying to find workarounds for not being able to access swift's built in SwiftSyntax. That's why I wrote Swift macros without requiring swift-syntax last year and why I tried to discuss Passing Syntax directly to the macro without swift-syntax a few days ago, and this project, and I assume many more POCs.

Alas, I'm not sure what that means for [Macros] Add support for wasm macros by kabiroberai · Pull Request #73031 · apple/swift · GitHub as it seems the "official" position from Apple is that:

Maybe it's time to ship SwiftSyntax directly with swift as a binary library just like Foundation :man_shrugging:t2:


Wasm macros use SwiftSyntax (they just bake it into the Wasm binary) so the comment you linked shouldn’t have any consequence on them, if I’m interpreting your point correctly.