Cross compiling
Easiest way that i have found is to use cross. It cross-compilers in docker (or podman) containers, that it manages itself.
You can also use cargo directly 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)
- make sure to have your user in the
docker
group to avoid root.
You can get a list of supoprted 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 cross/README.md also has
a list.
Configuring cargo
If you are cross compiling, then you are most likely targeting a platform that you cant or dont want to compile on. Basically something less powerful
and common than say x86_64
(or at least I am). So you'll most likely want a statically linked binary. You dont 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).
- targets with
musl
are generally preferred for building statically linked binaries.
So you need to add that to cargo.toml
, which can live in a couple of places, the ones
that i use are
$HOME/.cargo/config.toml
$PWD/.cargo/config.toml
Note that youll sometimes see it referred to without the .toml
suffix as .cargo/config
-- thats 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:
amine ~/projects/robot $ 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
):
amine ~/projects/robot $ 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:
amine ~/projects/robot $ scp target/aarch64-unknown-linux-musl/release/hello_robot vacuum-robot:/data
hello_robot
[root@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