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/ 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:

rustflags = ["-C", "target-feature=+crt-static"]

# my vacuum cleaner
rustflags = ["-C", "target-feature=+crt-static"]

# my router
rustflags = ["-C", "target-feature=+crt-static"]

# my access point
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

[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