Cross compile Rust binary to Linux amd64 from Mac M1

July 9, 2023

Cross compile Rust application with target x86_64-unknown-linux-gnu from Mac M1

Rust supported multiple platform and architecture, https://rust-lang.github.io/rustup-components-history/, using the same target triple/triplet from LLVM:

<arch><sub_arch>-<vendor>-<sys>-<env>

If you already installed rust compiler using rustup you can get list installed target using:

$ rustup target list --installed
aarch64-apple-darwin
aarch64-unknown-linux-gnu
wasm32-unknown-unknown
wasm32-wasi

Setup

First install linux amd64 toolchain target using:

$ rustup target add x86_64-unknown-linux-gnu

Beside target toolchain, you also need linker build final executable. For mac to linux you can install

# install pre build cross compiling tool
$ brew install SergioBenitez/osxct/x86_64-unknown-linux-gnu

The project

Create a new rust project

$ cargo new xrun
     Created binary (application) `xrun` package
$ cd xrun
$ cargo r
   Compiling xrun v0.1.0 (/Users/sakti/dev/xrun)
    Finished dev [unoptimized + debuginfo] target(s) in 1.31s
     Running `target/debug/xrun`
Hello, world!

To test cross compiling work, we are going to use whoami crate to retrieve current user and environment.

$ cargo add whoami
$ cat src/main.rs
fn main() {
    println!(
        "User's Name            whoami::realname():    {}",
        whoami::realname(),
    );
    println!(
        "User's Username        whoami::username():    {}",
        whoami::username(),
    );
    println!(
        "User's Language        whoami::lang():        {:?}",
        whoami::lang().collect::<Vec<String>>(),
    );
    println!(
        "Device's Pretty Name   whoami::devicename():  {}",
        whoami::devicename(),
    );
    println!(
        "Device's Hostname      whoami::hostname():    {}",
        whoami::hostname(),
    );
    println!(
        "Device's Platform      whoami::platform():    {}",
        whoami::platform(),
    );
    println!(
        "Device's OS Distro     whoami::distro():      {}",
        whoami::distro(),
    );
    println!(
        "Device's Desktop Env.  whoami::desktop_env(): {}",
        whoami::desktop_env(),
    );
    println!(
        "Device's CPU Arch      whoami::arch():        {}",
        whoami::arch(),
    );
}
$ cargo r
User's Name            whoami::realname():    Sakti Dwi Cahyono
User's Username        whoami::username():    sakti
User's Language        whoami::lang():        [""]
Device's Pretty Name   whoami::devicename():  sakti mbp
Device's Hostname      whoami::hostname():    sakti-mbp.local
Device's Platform      whoami::platform():    Mac OS
Device's OS Distro     whoami::distro():      macOS 13.4.1
Device's Desktop Env.  whoami::desktop_env(): Aqua
Device's CPU Arch      whoami::arch():        arm64

Cross compile

To cross compile we need to set some environment variable CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER:

$ CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-unknown-linux-gnu-gcc cargo build --target=x86_64-unknown-linux-gnu
# result will placed in ./target/x86_64-unknown-linux-gnu
$ file target/x86_64-unknown-linux-gnu/debug/xrun
target/x86_64-unknown-linux-gnu/debug/xrun: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, with debug_info, not stripped

Testing

To test we run docker container with target platform linux/amd64.

$ docker run --platform linux/amd64 -v $(pwd)/target:/target --rm -ti ubuntu:latest /bin/bash
root@1b9b91907d10:/# /target/x86_64-unknown-linux-gnu/debug/xrun
User's Name            whoami::realname():    root
User's Username        whoami::username():    root
User's Language        whoami::lang():        [""]
Device's Pretty Name   whoami::devicename():  1b9b91907d10
Device's Hostname      whoami::hostname():    1b9b91907d10
Device's Platform      whoami::platform():    Linux
Device's OS Distro     whoami::distro():      Ubuntu 22.04.2 LTS
Device's Desktop Env.  whoami::desktop_env(): Unknown: Unknown
Device's CPU Arch      whoami::arch():        x86_64
root@1b9b91907d10:/#

Return to blog

footer