Has anyone successfully cross-compiled from Windows, without WSL/VMs?

I’ve seen several times people trying to cross-compile from Windows to Linux like this:

  1. rustup.exe target add linux-etc-etc
  2. Find that there’s no linker, and no libraries
  3. Give up on cross-compiling
  4. Switch to Linux VM or Ubuntu-on-Windows instead

Has anyone managed to avoid steps 3 and 4? Is there a working cross-linker for Windows?

1 Like

I do this for my hobby OS. The community has basically switched to lld for this purpose.

Yes, you can cross-compile Rust programs (on nightly) from Windows to Linux using the linux-musl target as long as none of the crates you use have any C dependencies / sources. You’ll need to add this to your .cargo/config:

[target.x86_64-unknown-linux-musl]
rustflags = ["-Z", "linker-flavor=ld.lld"]

You can then (after rustup target add x86_64-unknown-linux-musl) build with cargo build --release --target x86_64-unknown-linux-musl. This will produce static binaries which should run on any recent Linux variant.

I was even able to cross-compile a rocket hello-world this way some time ago, but for that I had to do a few extra steps because it contained a dependency using C sources that must be compiled with the CC crate. What I had to do was roughly this, if I remember correctly:

  1. Download the musl Linux sources and prepare its headers with make (need make for Windows from MinGW for this)
  2. Install LLVM, add clang to PATH
  3. Cross-build with these extra environment variables:
CC_x86_64-unknown-linux-musl=clang
CFLAGS_x86_64_unknown_linux_musl=-I C:\tools\musl\musl-1.1.18\target\usr\local\musl\include
2 Likes

I cross compile regularly from Windows to my custom target for UEFI using Visual Studio Command Prompt. Haven’t tried it for Linux though.

In case someone finds this today: The necessary entry in .cargo/config has once again changed:

[target.x86_64-unknown-linux-musl]
linker = "rust-lld"

rustflags = ["-Z", "linker-flavor=ld.lld"] is now rustflags = ["-C", "linker-flavor=ld.lld"], but you don’t actually need that anymore since it seems to be inferred automatically from the linker name.

1 Like