从Linux向Windows跨编译Rust应用程序

114

我正在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

很遗憾,它们都不起作用。它会给我一个关于缺少std库的错误。
$ 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上运行的方法?

1
请参见我的文本:https://gist.github.com/vi/883cacf09b57a8efe5bf - Vi.
6个回答

177

其他答案虽然技术上是正确的,但比必要的更难。没有必要使用rustc(实际上这是不鼓励的),只需使用cargo,您只需要rustupcargo和您发行版的mingw-w64。

添加目标(您也可以为任何您交叉编译的目标更改此内容):

rustup target add x86_64-pc-windows-gnu

你可以轻松地使用以下方法构建您的板条箱:

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

不需要在~/.cargo/config或其他任何地方进行操作。

编辑:只是想补充一下,虽然您可以使用上面的方法,但有时也可能会带来麻烦。我想补充一下,Rust工具团队还维护一个名为cross的项目:https://github.com/rust-embedded/cross这可能是另一个您想研究的解决方案。


1
我之前漏了target add,但这是今天的解答! - Maximilian Burszley
12
Cargo 构建失败,错误信息为 error: linker x86_64-w64-mingw32-gcc not found。我猜测你提供的指令可能有遗漏? - Yuri Geinish
20
在Debian上,还需要运行sudo apt-get install mingw-w64。否则,一切都完美地工作。 - Yuri Geinish
1
我得到了/usr/bin/x86_64-w64-mingw32-ld: cannot find -lPacket - let4be
15
安装 rustup toolchain install stable-x86_64-pc-windows-gnu 是否必要?它会打印以下警告信息:"warning: toolchain 'stable-x86_64-pc-windows-gnu' may not be able to run on this system." 和 "warning: If you meant to build software to target that platform, perhaps try rustup target add x86_64-pc-windows-gnu instead?"另外,如果我卸载工具链,交叉编译仍然正常运行。 - glyn
显示剩余7条评论

37
Rust发行版仅提供主机系统的编译库。但是,根据Arch Linux有关Rust的维基页面,您可以从下载目录中的Windows软件包中复制编译库(请注意,有i686和x86-64软件包),并将其放置在系统上的适当位置(在/usr/lib/rustlib/usr/local/lib/rustlib,具体取决于Rust的安装位置),安装mingw-w64-gcc和Wine,然后您就可以进行交叉编译。
如果您使用Cargo,则可以通过将以下内容添加到~/.cargo/config(其中$ARCH是您使用的架构)来告诉Cargo查找ar和链接器:
[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"

这是非常有用的帖子,但是:Debian软件包mingw-w64在指定路径中没有ar实用程序,我该在哪里找到它?在编译情况下,使用该实用程序是否必要?是否有一种方法可以将/usr/local/lib/rustlib指定为其他自定义路径? - Fedcomp
您可以运行 rustup 脚本(说明)以在另一个目录中安装 Rust(使用 --prefix=path)。此外,arbinutils-mingw-w64 包中,安装在 /usr/bin/$ARCH-w64-mingw32-ar - Francis Gagné
非常感谢您的有用回复!我感觉现在离成功更近了。现在唯一需要解决的问题是“undefined reference to `_Unwind_Resume'”,但这是另一个问题了。再次感谢您。 - Fedcomp
2
尝试显式地链接 libgcc_s.a(当然是针对Windows的那个)。 - Francis Gagné

26

更新 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,但是它对我不起作用

此外,当与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 ,请在窗口的空白处右键单击并选择 在此处打开命令窗口

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


同意,这些是清晰易懂的指示。请查看https://www.libsdl.org/release/获取最新版本(现在已更新至2.0.8),并相应更改。 - paddyg
1
这个实际上并不能直接运行,因为(a)路径中有一些错误(例如/projects/rust-sdl2与/rust-sdl2与~/rust-sdl),(b)它使用了rust-sdl2主分支的最新版本,但该版本已经无法与SDL2 2.0.4兼容,(c)sine.wav已经移动。但是经过一些小修复后,它确实可以工作! - Tom Anderson
@TomAnderson,你能修改我的答案让它现在可以工作吗? - rofrol
@TomAnderson 修正了路径,但现在无法构建 :( - rofrol

20

有一个基于Docker的解决方案,名为cross。所有必需的工具都在虚拟化环境中,因此您不需要为计算机安装其他软件包。请参阅支持的目标列表

从项目的自述文件中:

特点

  • cross提供了跨平台编译所需的所有组件,而不会影响到您的系统安装。
  • cross提供了一个环境、交叉工具链和交叉编译库,可以生成最便携的二进制文件。
  • "跨平台测试",cross可以测试针对i686和x86_64之外的架构的crate。
  • 支持稳定版、beta版和夜间版通道。

Dependencies

  • rustup
  • 要进行跨平台测试,需要支持binfmt_misc的Linux内核。

这两个容器引擎之一是必需的。如果都安装了,cross将默认使用docker。

  • Docker。请注意,在Linux上,非sudo用户需要加入docker组中。请阅读官方的安装后步骤。需要版本1.24或更高版本。
  • Podman。需要版本1.6.3或更高版本。

安装方法

$ cargo install cross

使用方法

cross 命令行界面与 Cargo 完全相同,但因为它依赖 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

1
非常感谢这个解决方案!我在从Windows交叉编译到树莓派时遇到了问题,出现了“找不到板条箱'std'...可能未安装'arm-unknown-linux-gnueabihf'目标”的错误,即使确认我已经使用rustup安装了该目标。这是迄今为止唯一有效的解决方案。 - ostrumvulpes

9
我用的解决方案是。它类似于已接受答案中的一个,但我不需要添加工具链。
rustup target add x86_64-pc-windows-gnu
cargo build --target x86_64-pc-windows-gnu

请参考文档以获取更多详细信息。


4
我在 Debian(测试版)上取得了成功,没有使用 Mingw 和 Wine,只需按照官方说明进行操作。看起来很吓人,但最终并没有那么难。
官方说明中还包含有关如何交叉编译 C/C++ 代码的信息。由于我没有这方面的需求,因此我实际上没有进行过测试。
官方说明中的一些要点需要注意。数字与官方说明中的数字匹配。
  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

对于交叉编译本身,我使用以下简单脚本(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一样使用脚本。希望这能对某些人有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接