将 Rust 应用程序从 Linux 交叉编译到 Windows

Cross-compile a Rust application from Linux to Windows

基本上,当我在 Linux 上开发时,我正在尝试将最简单的代码编译为 Windows。

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

我通过互联网搜索找到了这些命令:

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

可悲的是,none 其中有效果。它给我一个关于 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

有没有一种方法可以在 Linux 上编译将 运行 在 Windows 上编译的代码?

Rust 发行版仅为主机系统提供编译库。然而,根据 Arch Linux's wiki page on Rust, you could copy the compiled libraries from the Windows packages in the download directory(注意有 i686 和 x86-64 包)在你系统的适当位置(在 /usr/lib/rustlib/usr/local/lib/rustlib,取决于 Rust 的安装位置),安装 mingw-w64-gcc 和 Wine,你应该可以交叉编译。

如果您正在使用 Cargo,您可以通过将此添加到 ~/.cargo/config 来告诉 Cargo 在哪里寻找 ar 和链接器(其中 $ARCH 是您使用的架构) :

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

注意:具体路径可能因您的发行版而异。检查您的发行版中 mingw-w64 包(GCC 和 binutils)的文件列表。

然后你可以像这样使用 Cargo:

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

更新 2019-06-11

这对我来说失败了:

     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

也许这会有所帮助 https://github.com/rust-lang/rust/issues/44787

静态编译sdl2

有静态编译 sdl 的选项,但 didn't work for me

还有mixer is not included when used with bundled.

让我们交叉编译 rust-sdl2 项目中的示例,从 Ubuntu 到 Windows x86_64

~/.cargo/config

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

然后运行这个:

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 .

立即构建示例

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

或在第一次失败后停止:

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

运行

cargo build 会将二进制文件放入 target/x86_64-pc-windows-gnu/debug/examples/

复制需要的文件:

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/

然后将目录 target/x86_64-pc-windows-gnu/debug/examples/ 复制到您的 Windows 机器和 运行 exe 文件。

运行 在 cmd.exe

如果你想在 运行 运行 exe 文件时看到控制台输出,你可以 运行 它们来自 cmd.exe.

要在文件资源管理器的当前目录中打开 cmd.exe,请在 window 中的空白处右键单击并选择 Open command window here

使用 mingw 的回溯现在应该可以工作了——如果不使用 msvc https://github.com/rust-lang/rust/pull/39234

我在 Debian 上取得了成功(测试)没有使用 Mingw 和 Wine 只是在 official instructions 之后。看着挺吓人的,不过最后也没那么痛

官方说明还包含有关如何交叉编译 C/C++ 代码的信息。我不需要那个,所以这是我还没有实际测试过的东西。

对官方说明中个别要点的几点说明。这些数字与 official instructions.

中的数字匹配
  1. Debian:sudo apt-get install lld
  2. 在您的 $PATH 中的某个地方创建一个名为 lld-link 的符号链接到 lld 。示例:ln -s /usr/bin/lld local_bin/lld-link
  3. 我不会交叉编译C/C++,这点个人没用过
  4. 这可能是最烦人的部分。我通过 rustup 在 Windows 盒子上安装了 Rust,并将库从官方文档中命名的目录复制到 Linux 盒子。当心,有时会有大写的库文件名,但 lld 希望它们全部小写(Windows 不区分大小写,Linux 是)。我使用以下命令将当前目录中的所有文件重命名为小写:

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

    就个人而言,我需要 Kit 目录和 VC 目录之一。

  5. 我不会交叉编译C/C++,这点个人没用过
  6. 把这个post末尾脚本中的$LIB_ROOT指向第3点的lib目录即可。
  7. 强制性
  8. 我不会交叉编译C/C++,这点个人没用过
  9. 根据目标体系结构,执行以下操作之一:
    • rustup target add i686-pc-windows-msvc
    • rustup target add x86_64-pc-windows-msvc

对于交叉构建本身,我使用以下简单脚本(32 位版本):

#!/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 "$@"

我使用脚本的方式与我使用脚本的方式相同 cargo build

希望对某人有所帮助!

其他答案虽然在技术上是正确的,但比他们需要的更难。没必要用rustc(其实不提倡,直接用cargo),你只需要rustupcargo和你发行版的mingw-w64.

添加目标(您也可以针对交叉编译的目标更改此设置):

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

您可以使用以下方法轻松构建您的箱子:

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

没必要乱搞 ~/.cargo/config 或其他任何东西。

编辑:只是想补充一点,虽然您可以使用上面的内容,但有时也会让人头疼。我想补充一点,Rust 工具团队还维护着一个名为 cross 的项目:https://github.com/rust-embedded/cross 这可能是您想要研究的另一种解决方案

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.

来自项目的自述文件:

特点

  • cross 将提供交叉编译所需的所有成分,而无需触及您的系统安装。
  • cross 提供了一个环境、交叉工具链和交叉编译库,可生成最便携的二进制文件。
  • “交叉测试”,cross 可以测试除 i686 和 x86_64.
  • 以外的架构的 crate
  • 支持稳定版、测试版和夜间频道。

依赖关系

  • rustup
  • 交叉测试需要具有 binfmt_misc 支持的 Linux 内核。

需要其中一个容器引擎。如果两者都安装,cross 将默认为 docker。

  • Docker。请注意,在 Linux non-sudo 上,用户需要在 docker 组中。阅读官方 post-installation 步骤。需要 1.24 或更高版本。
  • 豆荚人。需要 1.6.3 或更高版本。

安装

$ cargo install cross

用法

cross 具有与 Cargo 完全相同的 CLI,但由于它依赖于 Docker,您必须先启动守护进程才能使用它。

# (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

对我有用的解决方案是。它类似于接受的答案之一,但我不需要添加工具链。

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

详情请参阅documentation