Cross-compile a Rust application from Linux to Win

2019-03-08 11:00发布

问题:

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?

回答1:

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"


回答2:

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-nursery/rustup.rs
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
wget https://www.libsdl.org/release/SDL2-devel-2.0.4-mingw.tar.gz -P /tmp
tar xf /tmp/SDL2-devel-2.0.4-mingw.tar.gz -C /tmp

# Prepare files for building

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

# Build examples

# we use loop for...in because there is no such feature in cargo to build all examples at once
for i in examples/*; do 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 ~/rust-sdl/target/x86_64-pc-windows-gnu/debug/examples/
cp ~/rust-sdl/tests/sine.wav ~/rust-sdl/target/x86_64-pc-windows-gnu/debug/examples/

Then copy directory ~/rust-sdl/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.

No backtraces with mingw - use msvc

In the meantime if you do want backtraces and don't mind installing VC++ you can always use the x86_64-pc-windows-msvc version of Rust.

https://github.com/rust-lang/rust/issues/33985#issuecomment-222826116



回答3:

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.

A couple of remarks for individual points 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 need to cross-compile C/C++, don't have experience.
  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.

  1. I don't need to cross-compile C/C++, don't have experience.
  2. Just make $LIB_ROOT in the script at the end of this post point to the lib directory from point 4.
  3. Mandatory
  4. I don't need to cross-compile C/C++, don't have experience.
  5. 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!