Zig Makes Rust Cross-compilation Just Work
This post is a spiritual successor to Loris Cro’s Go cross-compilation.
During a recent stage 2 meeting Jakub Konka wanted to demo his progress on WASM support, but ran into problems with screen-sharing on Linux. After switching to his Mac to run it there, he found out that Wasmtime (a WASM runtime) doesn’t ship
aarch64-macos pre-built binaries.
But Wasmtime is an open-source Rust project, I should be able to clone the repo and build it for Jakub myself. The problem? I don’t have an M1 Mac on hand. I will have to cross-compile.
Rust has built-in cross-compilation support. All you have to do is install the target’s toolchain with
rustup target add aarch64-apple-darwin
and build your program with
cargo build --target aarch64-apple-darwin
The C dependencies
warning: cc: error: unrecognized command-line option `-arch` error: failed to run custom build command for `wasmtime-fiber` Caused by: ... running "cc" ...
Some Rust crates depend on C code, but the Rust toolchain does not include a C compiler. This is the same problem Loris encountered with CGO and, luckily for us, it has the same solution. Create a shell script which wraps Zig1
#!/bin/sh /path-to-zig/zig cc -target aarch64-macos $@
and add it to env variables as
CC when invoking
CC="/path-to-wrapper/zcc" cargo build --target aarch64-apple-darwin
error: linking with `cc` failed: exit code: 1 | = note: "cc" ...
We’re now successfully compiling Wasmtime’s objects, but we’re failing at the last step - linking the final binary.
The Rust toolchain includes the Rust standard library and a compiler to produce object files for the target, but it does not include a linker to link them into the final executable. Furthermore, the
cargo documentation instructs us to provide it with a target linker in
.cargo/config.toml. However, we can see that
cargo is attempting to invoke
cc like it did before with
wasmtime-fiber. Can we reuse the same wrapper we used before?
[target.aarch64-apple-darwin] linker = "/path-to-wrapper/zcc"
Success! This is a WASM “Hello, World!” example running on Wasmtime on Jakub’s M1, but the Wasmtime binary was compiled inside WSL on my x86_64 PC3. Pretty wild.
I’m using absolute paths to refer to
zigbecause I don’t want to add nighlty binaries into
$PATH. I recommend switching to system-wide install once the 0.8.0 branch gets released. ↩︎
aarch64-macossupport we’re interested in Zig’s self-hosted linker, which is slated for release in 0.8.0. I’m using the latest build from Zig’s download section. Built on 2021-05-20. All newer builds should work. ↩︎
This method of cross-compiling Rust is not limited to aarch64 MacOS from x86_64 Linux. If your host and target is supported by Rust and Zig, just change their
targetarguments and install Rust’s toolchain. You don’t have to install additional
gcctoolchains for each target. ↩︎