【问题标题】:Cross-compile a Rust application from Linux to Windows将 Rust 应用程序从 Linux 交叉编译到 Windows
【发布时间】:2021-12-30 00:32:54
【问题描述】:

基本上,我在 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 crate 丢失的错误

$ 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 上运行的代码?

【问题讨论】:

标签: linux windows rust cross-compiling


【解决方案1】:

其他答案虽然在技术上是正确的,但比他们需要的更难。没有必要使用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 这可能是您想要研究的另一种解决方案

【讨论】:

  • 我错过了target add,但这是今天的答案; ?!
  • 是的,我可以走得更远,但现在卡住了:pkg-config 尚未配置为支持交叉编译。为目标平台安装 sysroot 并通过 PKG_CONFIG_SYSROOT_DIR 和 PKG_CONFIG_PATH 进行配置,或者为 pkg-config 安装交叉编译包装器并通过 PKG_CONFIG 环境变量进行设置。
  • Cargo 以 error: linker x86_64-w64-mingw32-gcc not found 失败。我猜您的说明中缺少某些步骤?
  • 在 Debian 上,还需要 sudo apt-get install mingw-w64。否则,工作得很好。
  • rustup toolchain install stable-x86_64-pc-windows-gnu 有必要吗?它打印了消息“警告:工具链'stable-x86_64-pc-windows-gnu'可能无法在此系统上运行。”和“警告:如果您打算构建针对该平台的软件,也许可以试试rustup target add x86_64-pc-windows-gnu?”另外,如果我卸载工具链,交叉编译仍然可以正常工作。
【解决方案2】:

Rust 发行版只为主机系统提供编译库。但是,根据Arch Linux's wiki page on Rust,您可以在系统上的适当位置(在/usr/lib/rustlib 或@987654325 @,取决于 Rust 的安装位置),安装 mingw-w64-gcc 和 Wine,你应该可以交叉编译。

如果您使用 Cargo,您可以告诉 Cargo 在哪里寻找 ar 和链接器,方法是将其添加到 ~/.cargo/config(其中 $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"

【讨论】:

  • 这是非常有用的帖子,但是:debian 包 mingw-w64 在指定路径中没有 ar 实用程序,我在哪里可以找到它?是否有必要使用该实用程序以及它在编译案例中的作用?有没有办法将/usr/local/lib/rustlib 指定为其他自定义路径?
  • 您可以运行 rustup 脚本 (instructions) 将 Rust 安装在另一个目录中(使用 --prefix=path)。此外,ar 位于binutils-mingw-w64 包中,安装在/usr/bin/$ARCH-w64-mingw32-ar
  • 非常感谢您的有用回复!我觉得我现在更接近了。我所要克服的是对“_Unwind_Resume”的未定义引用,但这是另一个问题。再次感谢您。
  • 尝试明确地与libgcc_s.a 链接(当然是Windows 的那个)。
【解决方案3】:

更新 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,请在窗口中的空白处右键单击并选择Open command window here

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

【讨论】:

  • 同意,这些都是很好的明确说明。查看libsdl.org/release 获取最新版本(现在最高为 2.0.8)并进行相应更改
  • 这实际上并不能按原样工作,因为 (a) 路径中有一些错误(例如 ~/projects/rust-sdl2 vs ~/rust-sdl2 vs ~/rust- sdl),(b) 它使用 rust-sdl2 的 master 分支的尖端,它不再适用于 SDL2 2.0.4,并且 (c) sine.wav 已移动。但经过一些小修复后,它确实有效!
  • @TomAnderson 你能修改我的答案,让它现在可以工作吗?
  • @TomAnderson 修复了路径,但现在无法构建 :(
【解决方案4】:

有一个基于Docker 的解决方案称为cross。所有必需的工具都在虚拟化环境中,因此您无需为您的机器安装额外的软件包。见Supported targets list

来自项目的自述文件:

特点

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

依赖关系

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

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

  • 码头工人。请注意,在 Linux 上,非 sudo 用户需要在 docker 组中。阅读官方安装后步骤。需要 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

【讨论】:

  • 非常感谢这个解决方案!我在使用can't find crate 'std' ... the 'arm-unknown-linux-gnueabihf' target may not be installed 从 Windows 交叉编译到 Raspberry Pi 时遇到了问题,即使在确认我使用rustup 安装了目标之后也是如此。这是迄今为止唯一对我有用的解决方案。
【解决方案5】:

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

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

详情请参阅documentation

【讨论】:

    【解决方案6】:

    我在 Debian(测试)上取得了成功没有使用 Mingw 和 Wine,只是遵循 official instructions。它们看起来很吓人,但最终并没有那么痛。

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

    对官方说明中的各个点的几点说明。这些数字与official instructions 中的数字匹配。

    1. Debian:sudo apt-get install lld
    2. 在您的 $PATH 中的某处创建一个名为 lld-linklld 的符号链接。示例: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. 只需在本文末尾的脚本中将$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 的方式相同

    希望对某人有所帮助!

    【讨论】:

      猜你喜欢
      • 2017-02-03
      • 1970-01-01
      • 1970-01-01
      • 2020-01-28
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 2023-01-27
      相关资源
      最近更新 更多