Docs: Expand cross compiling section into its own page (#5284)

And fill out everything needed for all non-x64 targets supported by Wasmtime and
Cranelift.
This commit is contained in:
Nick Fitzgerald
2022-11-16 15:49:09 -08:00
committed by GitHub
parent 4780bd5902
commit 54a290cd53
3 changed files with 101 additions and 112 deletions

View File

@@ -55,6 +55,7 @@
- [Testing](./contributing-testing.md)
- [Fuzzing](./contributing-fuzzing.md)
- [CI](./contributing-ci.md)
- [Cross Compiling](./contributing-cross-compiling.md)
- [Coding Guidelines](./contributing-coding-guidelines.md)
- [Development Process](./contributing-development-process.md)
- [Release Process](./contributing-release-process.md)

View File

@@ -82,115 +82,3 @@ there, without needing to supply the `-p` flag:
cd crates/jit/
cargo build
```
## Cross Compiling Wasmtime
By default `cargo build` will build Wasmtime for the platform you're running the
build on. You might, however, want to build Wasmtime for a different platform!
Let's say for example that you want to build Wasmtime for
`aarch64-unknown-linux-gnu`. First you'll want to acquire the Rust standard
library for this target:
```shell
rustup target add aarch64-unknown-linux-gnu
```
Next you need to install a native C toolchain which has a C compiler, runtime
libraries, and linker for the desired target. This is unfortunately not very
easy to acquire on most platforms:
* On Windows you can install build tools for AArch64 Windows, but targeting
platforms like Linux or macOS is not easy. While toolchains exist for
targeting non-Windows platforms you'll have to hunt yourself to find the right
one.
* On macOS you can install, through Xcode, toolchains for iOS but the main
`x86_64-apple-darwin` is really the only easy target to install. You'll need
to hunt for toolchains if you want to compile for Linux or Windows.
* On Linux you can relatively easily compile for other Linux architectures most
of the time. For example on Debian-based distributions you can install the
`gcc-aarch64-linux-gnu` package which should come with the C compiler, runtime
libraries, and linker all in one (assuming you don't explicitly request
disabling recommended packages). Other Linux distributions may have
differently named toolchains. Compiling for macOS from Linux will require
finding your own toolchain. Compiling for Windows MSVC will require finding
your own toolchain, but compiling for MinGW can work easily enough if you
install the MinGW toolchain via your package manager.
For now we'll assume you're on Linux compiling for a different Linux
architecture. Once you've got the native toolchain, you'll want to find the C
compiler that came with it. On Debian, for example, this is called
`aarch64-linux-gnu-gcc`. Next up you'll need to configure two environment
variables to configure the Rust build:
```shell
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc
```
The first environment variable tells Cargo to tell rustc what the correct linker
for your target is. The second configures the [`cc` Rust
crate](https://crates.io/crates/cc) for C code compiled as part of the build.
Finally you can execute.
```shell
cargo build --target aarch64-unknown-linux-gnu --release
```
The built executable will be located at
`target/aarch64-unknown-linux-gnu/release/wasmtime`. Note that you can
cross-compile the C API in the same manner as the CLI too.
Note that if you are using these invocations regularly, you can avoid the need
to set environment variables by adding some configuration to your persistent
Cargo configuration. In the file `~/.cargo/config.toml` (in your home
directory), add the section:
```plain
[target.aarch64-unknown-linux-gnu]
linker = 'aarch64-linux-gnu-gcc'
```
Then the above `cargo build --target aarch64-unknown-linux-gnu` command should
work without setting any extra environment variables beforehand.
## Running a Cross-Compiled Wasmtime in qemu (emulation)
Once you have cross-compiled a binary, it is possible to run it on an emulator
if you do not have access to (or do not wish to use) hardware with the given
architecture. This can be done using an emulator such as `qemu`. The `qemu`
user-space emulation support allows running, for example, a Linux/aarch64
binary on a Linux/x86-64 host, as long as you have the system libraries for
aarch64 as well.
To try this out, first install `qemu`, making sure that the user-space emulator
option for your target architecture is enabled. On Debian-based Linux
distributions (including Ubuntu), this is in the `qemu-user` package, for
example.
Next, make sure that you have system libraries for the target. You will already
have these present if you cross-compiled as described above.
Finally, you can run the `wasmtime` binary under `qemu`; the following example
is for an `aarch64` target. Adjust the library paths as appropriate; these are
correct for Ubuntu/Debian's cross-compilation packages.
```shell
qemu-aarch64 \
-L /usr/aarch64-linux-gnu \
-E LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib \
target/aarch64-unknown-linux-gnu/release/wasmtime [ARGS]
```
You can add this to your persistent Cargo configuration as well. Extending the
above example in `~/.cargo/config.toml`, you can add:
```plain
[target.aarch64-unknown-linux-gnu]
linker = 'aarch64-linux-gnu-gcc'
runner = "qemu-aarch64 -L /usr/aarch64-linux-gnu -E LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib"
```
Then a simple `cargo test --target aarch64-unknown-linux-gnu` should work.

View File

@@ -0,0 +1,100 @@
# Cross Compiling
When contributing to Wasmtime and Cranelift you may run into issues that only
reproduce on a different architecture from your development machine. Luckily,
`cargo` makes cross compilation and running tests under [QEMU] pretty easy.
[QEMU]: https://www.qemu.org/
This guide will assume you are on an x86-64 with Ubuntu/Debian as your OS. The
basic approach (with commands, paths, and package names appropriately tweaked)
applies to other Linux distributions as well.
On Windows you can install build tools for AArch64 Windows, but targeting
platforms like Linux or macOS is not easy. While toolchains exist for targeting
non-Windows platforms you'll have to hunt yourself to find the right one.
On macOS you can install, through Xcode, toolchains for iOS but the main
`x86_64-apple-darwin` is really the only easy target to install. You'll need to
hunt for toolchains if you want to compile for Linux or Windows.
## Install Rust Targets
First, use `rustup` to install Rust targets for the other architectures that
Wasmtime and Cranelift support:
```shell
$ rustup target add \
s390x-unknown-linux-gnu \
riscv64gc-unknown-linux-gnu \
aarch64-unknown-linux-gnu
```
## Install GCC Cross-Compilation Toolchains
Next, you'll need to install a `gcc` for each cross-compilation target to serve
as a linker for `rustc`.
```shell
$ sudo apt install \
gcc-s390x-linux-gnu \
gcc-riscv64-linux-gnu \
gcc-aarch64-linux-gnu
```
## Install `qemu`
You will also need to install `qemu` to emulate the cross-compilation targets.
```shell
$ sudo apt install qemu-user
```
## Configure Cargo
The final bit to get out of the way is to configure `cargo` to use the
appropriate `gcc` and `qemu` when cross-compiling and running tests for other
architectures.
Add this to `.cargo/config.toml` in the Wasmtime repository (or create that file
if none already exists).
```toml
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
runner = "qemu-aarch64 -L /usr/aarch64-linux-gnu -E LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib -E WASMTIME_TEST_NO_HOG_MEMORY=1"
[target.riscv64gc-unknown-linux-gnu]
linker = "riscv64-linux-gnu-gcc"
runner = "qemu-riscv64 -L /usr/riscv64-linux-gnu -E LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/lib -E WASMTIME_TEST_NO_HOG_MEMORY=1"
[target.s390x-unknown-linux-gnu]
linker = "s390x-linux-gnu-gcc"
runner = "qemu-s390x -L /usr/s390x-linux-gnu -E LD_LIBRARY_PATH=/usr/s390x-linux-gnu/lib -E WASMTIME_TEST_NO_HOG_MEMORY=1"
```
## Cross-Compile Tests and Run Them!
Now you can use `cargo build`, `cargo run`, and `cargo test` as you normally
would for any crate inside the Wasmtime repository, just add the appropriate
`--target` flag!
A few examples:
* Build the `wasmtime` binary for `aarch64`:
```shell
$ cargo build --target aarch64-unknown-linux-gnu
```
* Run the tests under `riscv` emulation:
```shell
$ cargo test --target riscv64gc-unknown-linux-gnu
```
* Run the `wasmtime` binary under `s390x` emulation:
```shell
$ cargo run --target s390x-unknown-linux-gnu -- compile example.wasm
```