Cross compiling in Rust
Overview
Easiest way that I have found is to use cross. It cross-compilers in docker (or podman) containers, that it manages itself.
$ cargo install cross
You can also use cargodirectly with
cargo build --target=$target
, but I havent given that more than a cursory
attempt (but I should, to understand how cross
relates to cargo
better).
You can get a list of supported targets (platforms?) from rustc
:
$ rustc --print target-list
For more details on the different targets and how well they are supported,
check the rustc
documentation about about Platform suppport and
the for cross
specifically, the README.md
also has a list.
Configuring cargo
If you are cross compiling, then you are most likely targeting a platform that
you can't or don't want to compile on and most likley you'l want a statically
linked binary. You don't configure that in Cargo.toml
, because that is for
configuration of your project itself, and we need to configure cargo
(not the
project that it is building).
So you need to add that to cargo.toml
, recommended paths are:
$HOME/.cargo/config.toml
$PWD/.cargo/config.toml
Sometimes config.toml
referred to without the .toml
suffix as .cargo/config
-- that's a legacy name for the same file.
Making static builds
To get a static build, you need to pass -C target-feature=+crt-static
to rustc
. So if you're running rustc
directly, this should work:
$ rustc -C target-feature=+crt-static
But you probably arent, and you probably want to use the cargo config. If you use the cargo config, you can specify options for multiple targets in the same place, which is kind of neat:
[target.x86_64-unknown-linux-musl]
rustflags = ["-C", "target-feature=+crt-static"]
# my vacuum cleaner
[target.aarch64-unknown-linux-musl]
rustflags = ["-C", "target-feature=+crt-static"]
# my router
[target.armv7-unknown-linux-musleabihf]
rustflags = ["-C", "target-feature=+crt-static"]
# my access point
[target.mips-unknown-linux-musl]
rustflags = ["-C", "target-feature=+crt-static"]
Then to compile, say for my vacuum cleaner:
$ cross build --target aarch64-unknown-linux-musl --release
Compiling hello_robot v0.1.0 (/project)
Finished release [optimized] target(s) in 0.16s
You'll find the compiled binary in target/${target}/release
(assuming you built with --release
):
$ file target/aarch64-unknown-linux-musl/release/hello_robot
target/aarch64-unknown-linux-musl/release/hello_robot: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, with debug_info, not stripped
Transfer it somehow to the machine with the architectory you targetted, and it will .. just work:
localhost$ scp target/aarch64-unknown-linux-musl/release/hello_robot vacuum-robot:/data
hello_robot
vacuum-robot# /data/hello_robot
Hello, world!
As a sidenote, if you have a robot vacuum and you havent rooted it, then you are missing out.
Useful commands
If youre somewhere without rust installed, can can use the docker images. To get the list of supported targets for example:
$ docker run --rm \
--user "$(id -u)":"$(id -g)" \
rust:latest rustc --print target-list