I’ve been using Rust recently to cross compile geckodriver from 64-bit Linux to different architectures and toolchains such as Windows, ARM, FreeBSD, 32-bit Linux, and musl. My conclusion so far is that Rust does not provide the best experience for cross compilation compared to some other languages: Go in particular shines in this area, where % env GOOS=window go build hello.go
will just do the right thing.
However, if you combine Rust with rustup, it will give you an easy way to install new compile targets. Each of the installed targets can in turn be passed to cargo build --target TARGET
making it rather easy to do cross compilation for alternative architectures that are well supported on your system.
For example, to produce a 32-bit executable on a 64-bit Linux system:
# dpkg --add-architecture i386
# apt update
% rustup target add i686-unknown-linux-gnu
% cargo build --target i686-unknown-linux-gnu
It gets more complicated when you need to use alternative linkers, for example when cross compiling to Windows:
# apt install gcc-mingw-w64 gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64
% rustup target add x86_64-pc-windows-gnu
% cat >>.cargo/config <<EOF
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
EOF
% cargo build --target x86_64-pc-windows-gnu
In my opinion it’s a mistake to not allow -C linker=LINKER
to be passed through to rustc from the cargo UI. In continuous integration environments, that are typically one-off throwaway virtual machines, it would save a lot of effort if you did not have to write to the cargo config file.
There are also some targets that I’m being told it’s not possible to cross compile to, such as macOS. I would love for someone more familiar with linkers and macOS to share more insight on this. For those of us writing userland programs for wide distribution across different architectures and platforms, being able to cross-compile statically linked executables to each of the major operating systems would be extremely helpful.