Coder Perfect

From Linux to Windows, cross-compile a Rust program

Problem

I’m attempting to compile the most basic code to Windows while coding on Linux.

fn main() {
    println!("Hello, and bye.")
}

These commands came from a search on the internet:

rustc --target=i686-w64-mingw32-gcc  main.rs
rustc --target=i686_pc_windows_gnu -C linker=i686-w64-mingw32-gcc  main.rs

Unfortunately, none of them work. It complains about the standard crate being missing.

$ rustc --target=i686_pc_windows_gnu -C linker=i686-w64-mingw32-gcc  main.rs 

main.rs:1:1: 1:1 error: can't find crate for `std`
main.rs:1 fn main() {
          ^
error: aborting due to previous error

Is it possible to compile Linux code that will run on Windows?

Asked by Fedcomp

Solution #1

While other answers are technically correct, they are more complex than necessary. You don’t require rustc (in fact, it’s discouraged; instead, use cargo); all you need is rustup, cargo, and your distribution’s mingw-w64.

Add the target (which you can modify to whatever target you’re cross-compiling for):

rustup target add x86_64-pc-windows-gnu
rustup toolchain install stable-x86_64-pc-windows-gnu

You may easily construct your crate using the following materials:

cargo build --target x86_64-pc-windows-gnu

There’s no need to fiddle with /.cargo/config or anything else.

EDIT: I just wanted to point out that while you can use the above, it can also be a pain. I’d like to point out that the rust tools team also maintains a cross: https://github.com/rust-embedded/cross Another option to consider is https://github.com/rust-embedded/cross

Answered by zee

Solution #2

Only compiled libraries for the host system are included in the Rust distribution. However, according to the Arch Linux wiki page on Rust, you can cross-compile by copying the compiled libraries from the Windows packages in the download directory (note that there are i686 and x86-64 packages), installing mingw-w64-gcc, and installing Wine in the appropriate place on your system (in /usr/lib/rustlib or /usr/local/lib/rustlib, depending on where Rust is installed).

If you’re using Cargo, you can instruct it where to look for ar and the linker by adding the following to your /.cargo/config (where $ARCH is your architecture):

[target.$ARCH-pc-windows-gnu]
linker = "/usr/bin/$ARCH-w64-mingw32-gcc"
ar = "/usr/$ARCH-w64-mingw32/bin/ar"

Note that depending on your distribution, the exact pathways may differ. Check your distribution’s file list for the mingw-w64 package(s) (GCC and binutils).

Then you can use Cargo in the following way:

$ # Build
$ cargo build --release --target "$ARCH-pc-windows-gnu"
$ # Run unit tests under wine
$ cargo test --target "$ARCH-pc-windows-gnu"

Answered by Francis Gagné

Solution #3

UPDATE 2019-06-11

This doesn’t work for me because:

     Running `rustc --crate-name animation examples/animation.rs --color always --crate-type bin --emit=dep-info,link -C debuginfo=2 --cfg 'feature="default"' -C metadata=006e668c6384c29b -C extra-filename=-006e668c6384c29b --out-dir /home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/examples --target x86_64-pc-windows-gnu -C ar=x86_64-w64-mingw32-gcc-ar -C linker=x86_64-w64-mingw32-gcc -C incremental=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/incremental -L dependency=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps -L dependency=/home/roman/projects/rust-sdl2/target/debug/deps --extern bitflags=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps/libbitflags-2c7b3e3d10e1e0dd.rlib --extern lazy_static=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps/liblazy_static-a80335916d5ac241.rlib --extern libc=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps/liblibc-387157ce7a56c1ec.rlib --extern num=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps/libnum-18ac2d75a7462b42.rlib --extern rand=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps/librand-7cf254de4aeeab70.rlib --extern sdl2=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps/libsdl2-3f37ebe30a087396.rlib --extern sdl2_sys=/home/roman/projects/rust-sdl2/target/x86_64-pc-windows-gnu/debug/deps/libsdl2_sys-3edefe52781ad7ef.rlib -L native=/home/roman/.cargo/registry/src/github.com-1ecc6299db9ec823/winapi-x86_64-pc-windows-gnu-0.4.0/lib`
error: linking with `x86_64-w64-mingw32-gcc` failed: exit code: 1

Perhaps this will be of assistance. https://github.com/rust-lang/rust/issues/44787

Static-compiling sdl is a possibility, however it didn’t work for me.

Also, while using the packaged, the mixer is not included.

In ~/.cargo/config

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-gcc-ar"

Then run this:

sudo apt-get install gcc-mingw-w64-x86-64 -y
# use rustup to add target https://github.com/rust-lang/rustup.rs#cross-compilation
rustup target add x86_64-pc-windows-gnu

# Based on instructions from https://github.com/AngryLawyer/rust-sdl2/

# First we need sdl2 libs
# links to packages https://www.libsdl.org/download-2.0.php

sudo apt-get install libsdl2-dev -y
curl -s https://www.libsdl.org/release/SDL2-devel-2.0.9-mingw.tar.gz | tar xvz -C /tmp

# Prepare files for building

mkdir -p ~/projects
cd ~/projects
git clone https://github.com/Rust-SDL2/rust-sdl2
cd rust-sdl2
cp -r /tmp/SDL2-2.0.9/x86_64-w64-mingw32/lib/* ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/
cp /tmp/SDL2-2.0.9/x86_64-w64-mingw32/bin/SDL2.dll .

Create multiple examples at the same time.

cargo build --target=x86_64-pc-windows-gnu --verbose --examples

Alternatively, you can stop after your first failure:

echo; for i in examples/*; do [ $? -eq 0 ] && cargo build --target=x86_64-pc-windows-gnu --verbose --example $(basename $i .rs); done

Binaries will be placed in target/x86 64-pc-windows-gnu/debug/examples/ by cargo build.

Copy needed files:

cp /tmp/SDL2-2.0.4/x86_64-w64-mingw32/bin/SDL2.dll target/x86_64-pc-windows-gnu/debug/examples/
cp assets/sine.wav target/x86_64-pc-windows-gnu/debug/examples/

Then, on your Windows system, copy the target/x86 64-pc-windows-gnu/debug/examples/ directory and run the exe files.

If you wish to see the console output when running exe files, you can use cmd.exe to do so.

In file explorer, right-click with shift on an empty space in the window and select Open command window here to open cmd.exe in the current directory.

Backtraces should now work with mingw; if not, use msvc (https://github.com/rust-lang/rust/pull/39234).

Answered by rofrol

Solution #4

Cross, a Docker-based solution, is available. Because all of the necessary tools are virtualized, you won’t need to install any additional packages on your PC. See the list of targets that are supported.

From project’s README:

It’s necessary to use one of these container engines. If both are installed, cross will use docker by default.

$ cargo install cross

Cross uses the same CLI as Cargo, but because it relies on Docker, you’ll need to run the daemon first.

# (ONCE PER BOOT)
# Start the Docker daemon, if it's not already running
$ sudo systemctl start docker

# MAGIC! This Just Works
$ cross build --target aarch64-unknown-linux-gnu

# EVEN MORE MAGICAL! This also Just Works
$ cross test --target mips64-unknown-linux-gnuabi64

# Obviously, this also Just Works
$ cross rustc --target powerpc-unknown-linux-gnu --release -- -C lto

Answered by raspi

Solution #5

This was the solution that worked for me. Although it is identical to one of the allowed responses, I did not feel it necessary to provide the toolchain.

rustup target add x86_64-pc-windows-gnu
cargo build --target x86_64-pc-windows-gnu

For further information, see the documentation.

Answered by rbansal

Post is based on https://stackoverflow.com/questions/31492799/cross-compile-a-rust-application-from-linux-to-windows