111

Basically I'm trying to compile the simplest code to Windows while I am developing on Linux.

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

I found these commands by searching the internet:

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

Sadly, none of them work. It gives me an error about the std crate 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 there a way to compile code on Linux that will run on Windows?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Fedcomp
  • 2,175
  • 5
  • 21
  • 23

6 Answers6

173

Other answers, while technically correct, are more difficult than they need to be. There's no need to use rustc (in fact it's discouraged, just use cargo), you only need rustup, cargo and your distribution's mingw-w64.

Add the target (you can also change this for whatever target you're cross compiling for):

rustup target add x86_64-pc-windows-gnu

You can build your crate easily with:

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

No need for messing around with ~/.cargo/config or anything else.

EDIT: Just wanted to add that while you can use the above it can also sometimes be a headache. I wanted to add that the rust tools team also maintains a project called cross: https://github.com/rust-embedded/cross This might be another solution that you want to look into

Newbyte
  • 2,421
  • 5
  • 22
  • 45
zee
  • 2,933
  • 2
  • 16
  • 28
  • This is by far the best solution for keeping everything conform with cargo. That was very helpful for me – Cobalt Sep 24 '20 at 13:06
  • 1
    Yes, I could get more far, but now stuck with: pkg-config has not been configured to support cross-compilation. Install a sysroot for the target platform and configure it via PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a cross-compiling wrapper for pkg-config and set it via PKG_CONFIG environment variable. – veto Oct 18 '20 at 04:28
  • Could you point to or add a list of (common) targets? – Tony Jan 25 '21 at 15:28
  • 12
    Cargo fails with `error: linker x86_64-w64-mingw32-gcc not found` though. I guess some steps are missing from your instructions? – Yuri Geinish Jan 29 '21 at 22:18
  • 19
    On Debian, `sudo apt-get install mingw-w64` is also needed. Otherwise, works perfectly fine. – Yuri Geinish Jan 29 '21 at 22:49
  • @YuriGeinish I'll add that to the list of instructions thank you :D – zee Jan 31 '21 at 00:07
  • @Tony this is build into rust, you can just do `rustc --print target-list`. Also after trying both I'd highly recommend using cross. – zee Jan 31 '21 at 00:08
  • when i first asked a question there was no such simple way to do it, i marked your answer as accepted, thank you. – Fedcomp Mar 02 '21 at 08:04
  • cross works like a charm (for cross-compiling a DLL for Windows on Ubuntu) – Frank Schmitt Mar 17 '21 at 20:49
  • 1
    I'm getting `/usr/bin/x86_64-w64-mingw32-ld: cannot find -lPacket` – let4be May 11 '21 at 10:53
  • 15
    Is `rustup toolchain install stable-x86_64-pc-windows-gnu` necessary? It printed the messages "warning: toolchain 'stable-x86_64-pc-windows-gnu' may not be able to run on this system." and "warning: If you meant to build software to target that platform, perhaps try `rustup target add x86_64-pc-windows-gnu` instead?" Also, if I uninstall the toolchain, the cross-compilation still works ok. – glyn Oct 26 '21 at 15:08
37

The Rust distribution only provides compiled libraries for the host system. However, according to Arch Linux's wiki page on Rust, you could copy the compiled libraries from the Windows packages in the download directory (note that there are i686 and x86-64 packages) in the appropriate place on your system (in /usr/lib/rustlib or /usr/local/lib/rustlib, depending on where Rust is installed), install mingw-w64-gcc and Wine and you should be able to cross-compile.

If you're using Cargo, you can tell Cargo where to look for ar and the linker by adding this to ~/.cargo/config (where $ARCH is the architecture you use):

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

Note: the exact paths can vary based on your distribution. Check the list of files for the mingw-w64 package(s) (GCC and binutils) in your distribution.

Then you can use Cargo like this:

$ # Build
$ cargo build --release --target "$ARCH-pc-windows-gnu"
$ # Run unit tests under wine
$ cargo test --target "$ARCH-pc-windows-gnu"
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • That's very useful post, however: debian package mingw-w64 does not have ar utility in specified path, where i can find it? is it necessary to use that utility and what it does in compiling case? and is there a way to specify `/usr/local/lib/rustlib` as some other custom path? – Fedcomp Jul 18 '15 at 16:38
  • You can run the rustup script ([instructions](http://www.rust-lang.org/install.html)) to install Rust in another directory (with `--prefix=path`). Also, `ar` is in the `binutils-mingw-w64` package, installed at `/usr/bin/$ARCH-w64-mingw32-ar`. – Francis Gagné Jul 18 '15 at 16:57
  • Huge thank you for your useful responses! i feel like i'm a lot closer now. All i have to beat is undefined reference to `_Unwind_Resume', but it's another issue. Thank you again. – Fedcomp Jul 18 '15 at 17:18
  • 2
    Try linking with `libgcc_s.a` explicitly (the one for Windows, of course). – Francis Gagné Jul 18 '15 at 18:24
26

UPDATE 2019-06-11

This fails for me with:

     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

Maybe this will help https://github.com/rust-lang/rust/issues/44787

Static compile sdl2

There is option to static-compile sdl but it didn't work for me.

Also mixer is not included when used with bundled.

Let's cross-compile examples from rust-sdl2 project from Ubuntu to Windows x86_64

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 .

Build examples at once

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

Or stop after first fail:

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

Run

cargo build will put binaries in target/x86_64-pc-windows-gnu/debug/examples/

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 copy directory target/x86_64-pc-windows-gnu/debug/examples/ to your Windows machine and run exe files.

Run in cmd.exe

If you want to see the console output when running exe files, you may run them from cmd.exe.

To open cmd.exe in current directory in file explorer, right click with shift on empty place in window and choose Open command window here.

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

rofrol
  • 14,438
  • 7
  • 79
  • 77
  • Agree, these are good clear instructions. Check https://www.libsdl.org/release/ for the latest version (now up to 2.0.8) and change accordingly – paddyg Jul 21 '18 at 23:02
  • 1
    This doesn't actually quite work as-is, because (a) there are some mistakes in the paths (eg ~/projects/rust-sdl2 vs ~/rust-sdl2 vs ~/rust-sdl), (b) it uses the tip of the master branch of rust-sdl2, which no longer works with SDL2 2.0.4, and (c) sine.wav has moved. But after some minor fixes it does indeed work! – Tom Anderson Jan 11 '19 at 10:13
  • @TomAnderson Can you modify my answer so that it works now? – rofrol Jan 15 '19 at 13:35
  • @TomAnderson Fixed paths, but now it does not build :( – rofrol Jun 11 '19 at 09:32
19

There is Docker based solution called cross. All the required tools are in virtualized environment so you don't need to install additional packages for your machine. See Supported targets list.

From project's README:

Features

  • cross will provide all the ingredients needed for cross compilation without touching your system installation.
  • cross provides an environment, cross toolchain and cross compiled libraries, that produces the most portable binaries.
  • “cross testing”, cross can test crates for architectures other than i686 and x86_64.
  • The stable, beta and nightly channels are supported.

Dependencies

  • rustup
  • A Linux kernel with binfmt_misc support is required for cross testing.

One of these container engines is required. If both are installed, cross will default to docker.

  • Docker. Note that on Linux non-sudo users need to be in the docker group. Read the official post-installation steps. Requires version 1.24 or later.
  • Podman. Requires version 1.6.3 or later.

Installation

$ cargo install cross

Usage

cross has the exact same CLI as Cargo but as it relies on Docker you'll have to start the daemon before you can use it.

# (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
raspi
  • 5,962
  • 3
  • 34
  • 51
  • 1
    Thanks so much for this solution! I had issues cross-compiling from Windows to Raspberry Pi with `can't find crate 'std' ... the 'arm-unknown-linux-gnueabihf' target may not be installed`, even after confirming I had the target installed with `rustup`. This was the only solution that has worked for me so far. – ostrumvulpes Sep 24 '20 at 22:40
9

The solution that worked for me was. It is similar to one of the accepted answers but I did not require to add the toolchain.

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

Refer to the documentation for more details.

rbansal
  • 1,184
  • 14
  • 21
4

I've had success on Debian (testing) without using Mingw and Wine just following the official instructions. They look scary, but in the end it didn't hurt that much.

The official instructions also contain info on how to cross-compile C/C++ code. I haven't needed that, so it's something I haven't actually tested.

A couple of remarks for individual points in the official instructions. The numbers match the numbers in the official instructions.

  1. Debian: sudo apt-get install lld
  2. Make a symlink named lld-link to lld somewhere in your $PATH. Example: ln -s /usr/bin/lld local_bin/lld-link
  3. I don't cross-compile C/C++, haven't used this point personally.
  4. This is probably the most annoying part. I installed Rust on a Windows box via rustup, and copied the libraries from the directories named in the official docs to the Linux box. Beware, there were sometimes uppercase library filenames, but lld wants them all lowercase (Windows isn't case-sensitive, Linux is). I've used the following to rename all files in current directory to lowercase:

    for f in `find`; do mv -v "$f" "`echo $f | tr '[A-Z]' '[a-z]'`"; done
    

    Personally, I've needed both Kit directories and just one of the VC dirs.

  5. I don't cross-compile C/C++, haven't used this point personally.
  6. Just make $LIB_ROOT in the script at the end of this post point to the lib directory from point 3.
  7. Mandatory
  8. I don't cross-compile C/C++, haven't used this point personally.
  9. Depending the target architecture, either of the following:
    • rustup target add i686-pc-windows-msvc
    • rustup target add x86_64-pc-windows-msvc

For cross-building itself, I'm using the following simple script (32-bit version):

#!/bin/sh
# "cargo build" for the 32-bit Windows MSVC architecture.

# Set this to proper directory
LIB_ROOT=~/opt/rust-msvc

# The rest shouldn't need modifications
VS_LIBS="$LIB_ROOT/Microsoft Visual Studio 14.0/VC/lib/"
KIT_8_1_LIBS="$LIB_ROOT/Windows Kits/8.1/Lib/winv6.3/um/x86/"
KIT_10_LIBS="$LIB_ROOT/Windows Kits/10/Lib/10.0.10240.0/ucrt/x86/"
export LIB="$VS_LIBS;$KIT_8_1_LIBS;$KIT_10_LIBS"
cargo build --target=i686-pc-windows-msvc "$@"

I'm using the script the same way I would use cargo build

Hope that helps somebody!

Tomáš Dvořák
  • 1,490
  • 1
  • 9
  • 20