A journey through the issues I encountered
While trying to cross-compile rust from Mac to Linux I ran into a few issues, so I thought I would write a simple guide for myself and anyone else interested. This mainly consists of my own findings and might not work for everyone.
To cross-compile from one platform to another, it's usually not enough to just install the standard library for the target using rustup. You also have to install a linker for the platform and tell rustc
where to find it.
For some platforms, other dependencies might be necessary as well, but in this article, I will concentrate on compiling from Mac to Linux.
Generally, these are the steps necessary to compile from one platform to another:
rustup target add <target>
rustc
can find the linkerTARGET_CC
environment variable to the linker executable during compilationcargo build --release --target <target>
When choosing the right build target I had the choice between x86_64-unknown-linux-gnu
and x86_64-unknown-linux-musl
.
The musl
target produces a statically linked binary using the musl C standard library which aims to be very lightweight and simple. The benefit of statically linking the C standard library is that it will run on basically any modern Linux operating system with no dependencies. The drawback is that musl
is often quite a bit slower than glibc
and therefore not the optimal choice for many projects.
The gnu
target on the other hand produces a dynamically linked binary which depends on glibc
being installed on the host system.
Because glibc
is often a bit faster than musl
I decided to go with the gnu
target. But I will also explain how to build for the musl
target.
The first step is always to install the standard library using rustup
. This is simply done using rustup target add x86_64-unknown-linux-gnu
.
But to actually compile to the given target we also need a linker. For this we will use a homebrew formula provided by the community:
brew install SergioBenitez/osxct/x86_64-unknown-linux-gnu
Now that the linker is installed we need to tell rustc
where to find it. This can be done by updating the .cargo/config.toml and adding the linker for the target:
[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-gcc"
Now you might already be able to compile to the target using cargo build --target x86_64-unknown-linux-gnu
, but for many projects, it will also be necessary to set the TARGET_CC
environment variable to the linker executable. A full build command could therefore look like this:
TARGET_CC=x86_64-unknown-linux-gnu cargo build --release --target x86_64-unknown-linux-gnu
This is it! You can now cross-compile from Mac to Linux!
Keep in mind that the produced binary is dynamically linked, so you might need to install other dependencies on the host system to make the executable work.
First, we need to install the standard library using rustup
. This is simply done by running rustup target add x86_64-unknown-linux-musl
.
To actually compile to the given target we also need a linker. For this we will use a homebrew formular provided by the community:
brew install FiloSottile/musl-cross/musl-cross
Now that the linker is installed we need to tell rustc where to find it. This can be done by updating the .cargo/config.toml and adding the linker for the target:
[target.x86_64-unknown-linux-musl]
linker = "x86_64-linux-musl-gcc"
Now you might already be able to compile to the target using cargo build --target x86_64-unknown-linux-musl
, but for many projects it will also be necessary to set the TARGET_CC
environment variable to the linker executable. A full build command could therefore look like this:
TARGET_CC=x86_64-linux-musl-gcc cargo build --release --target x86_64-unknown-linux-musl
That's it! You can now cross-compile from Mac to Linux.
The produced binary is statically linked and should run on most modern Linux operating systems.