从Linux交叉编译Rust for Windows可执行文件

如果我在Habr IT网站上,这也许并不奇怪,我会说我有时会喜欢编程。


我的主要操作系统是Linux,但有时我也必须为Windows收集可执行文件。当然,我并不想真的只是为了执行exe程序而重启进入Windows。 C和C ++语言没有问题,很长一段时间以来,都有一个交叉编译器MinGW可以很好地完成此任务。关于PythonJava甚至不值得一提的,跨平台的最初它们。但是去年我决定尝试使用Rust这样的新型语言。使用Rust分发套件中包含的软件包管理器组装可执行文件时,cargo似乎足以指定一个密钥--target来指定生成的处理器,体系结构和ABI,并且从Linux构建时,获取exe(这将是Windows的标准可执行文件)。但尝试这样做:


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

我只收到链接器错误消息:


error: linking with `gcc` failed: exit code: 1

[...]

  = note: /usr/bin/ld: unrecognized option '--nxcompat'
          /usr/bin/ld: use the --help option for usage information
          collect2: error: ld returned 1 exit status

error: aborting due to previous error

error: could not compile `foobar`.

如果有人对我的克服方法感兴趣,现在我可以在不离开Linux的情况下轻松地为Windows交叉编译Rust程序,欢迎加入。


免责声明

32bit 64bit pc-windows-gnu, pc-windows-msvc . Linux, , Fedora Linux 31, Linux . Rust The Rust toolchain installer, Fedora Rust , nightly Rust, , , .


首先,我们通过运行以下命令确保已设置必要的目标:


rustup target list

我们会列出所有可能的目标以及已设定的目标:


aarch64-apple-ios
aarch64-fuchsia
[...]
i686-pc-windows-gnu (installed)
[...]
i686-unknown-linux-gnu (installed)
[...]
x86_64-pc-windows-gnu (installed)
x86_64-unknown-linux-gnu (installed)
[...]

要从Linux创建Windows的可执行文件,我们需要i686-pc-windows-gnu32位exe和x86_64-pc-windows-gnu64位exe的目标如果这些目标未标记为(installed),则我们使用以下命令来实现它们


rustup target add _

在确保通过MinGW运行以下命令安装了交叉编译器之后


rpm -qa | grep mingw

或我们Linux发行版的其他软件包管理器:


mingw32-gcc-9.2.1-1.fc31.x86_64
mingw32-binutils-2.32-6.fc31.x86_64
mingw64-gcc-9.2.1-1.fc31.x86_64
mingw-binutils-generic-2.32-6.fc31.x86_64
mingw-filesystem-base-110-1.fc31.noarch
mingw64-winpthreads-6.0.0-2.fc31.noarch
mingw32-winpthreads-6.0.0-2.fc31.noarch
mingw32-crt-6.0.0-2.fc31.noarch
mingw64-binutils-2.32-6.fc31.x86_64
mingw64-crt-6.0.0-2.fc31.noarch
mingw64-filesystem-110-1.fc31.noarch
mingw32-filesystem-110-1.fc31.noarch
mingw32-cpp-9.2.1-1.fc31.x86_64
mingw64-headers-6.0.0-2.fc31.noarch
mingw32-headers-6.0.0-2.fc31.noarch
mingw64-cpp-9.2.1-1.fc31.x86_64

如果没有,MinGW请通过运行以下步骤安装必要的软件包


sudo dnf install mingw32-gcc mingw64-gcc

, (, - Test-Driven Development, :-)


Rust:


[pfemidi@pfemidi rust]$ cargo new foobar
     Created binary (application) `foobar` package
[pfemidi@pfemidi rust]$ cat foobar/src/main.rs 
fn main() {
    println!("Hello, world!");
}
[pfemidi@pfemidi rust]$

Linux:


[pfemidi@pfemidi foobar]$ cargo run
   Compiling foobar v0.1.0 (/home/pfemidi/mywork/rust/foobar)
    Finished dev [unoptimized + debuginfo] target(s) in 1.65s
     Running `target/debug/foobar`
Hello, world!
[pfemidi@pfemidi foobar]$ 

. x86_64-pc-windows-gnu:


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

:


error: linking with `gcc` failed: exit code: 1

[...]

  = note: /usr/bin/ld: unrecognized option '--nxcompat'
          /usr/bin/ld: use the --help option for usage information
          collect2: error: ld returned 1 exit status

error: aborting due to previous error

error: could not compile `foobar`.

, MinGW, gcc. , .cargo config :


[pfemidi@pfemidi foobar]$ mkdir .cargo
[pfemidi@pfemidi foobar]$ cat > .cargo/config
[target.i686-pc-windows-gnu]
linker = "i686-w64-mingw32-gcc"
ar = "i686-w64-mingw32-ar"

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

Windows gcc, MinGW.


:


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

, x86_64-w64-mingw32-gcc:


error: linking with `x86_64-w64-mingw32-gcc` failed: exit code: 1

[...]

  = note: /usr/lib/gcc/x86_64-w64-mingw32/9.2.1/../../../../x86_64-w64-mingw32/bin/ld: cannot find -lpthread
          collect2: error: ld returned 1 exit status

error: aborting due to previous error

error: could not compile `foobar`.

, Rust - , mingw32-winpthreads mingw64-winpthreads, dnf mingw32-gcc mingw64-gcc mingw32-winpthreads-static mingw64-winpthreads-static, -lpthread . :


sudo dnf install mingw??-winpthreads-static

:


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

! :


error: linking with `x86_64-w64-mingw32-gcc` failed: exit code: 1

[...]

  = note: /usr/lib/gcc/x86_64-w64-mingw32/9.2.1/../../../../x86_64-w64-mingw32/bin/ld: /home/pfemidi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o:crtexe.c:(.rdata$.refptr.__onexitbegin[.refptr.__onexitbegin]+0x0): undefined reference to `__onexitbegin'
          /usr/lib/gcc/x86_64-w64-mingw32/9.2.1/../../../../x86_64-w64-mingw32/bin/ld: /home/pfemidi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o:crtexe.c:(.rdata$.refptr.__onexitend[.refptr.__onexitend]+0x0): undefined reference to `__onexitend'
          collect2: error: ld returned 1 exit status

error: aborting due to previous error

error: could not compile `foobar`.

__onexitbegin __onexitend ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/crt2.o, x86_64-pc-windows-gnu. , , Rust, Rust, Rust : Rust Windows, pc-windows-gnu, MinGW 6.3.0, Fedora Linux 31 MinGW 9.2.1, CRT. Ok, crt2.o MinGW Rust x86_64-pc-windows-gnu. crt2.o dllcrt2.o, :


[pfemidi@pfemidi foobar]$ cd ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/
[pfemidi@pfemidi lib]$ cp /usr/x86_64-w64-mingw32/sys-root/mingw/lib/crt2.o .
[pfemidi@pfemidi lib]$ cp /usr/x86_64-w64-mingw32/sys-root/mingw/lib/dllcrt2.o .
[pfemidi@pfemidi lib]$ cd -
/home/pfemidi/mywork/rust/foobar
[pfemidi@pfemidi foobar]$ 

Rust:


pfemidi@pfemidi foobar]$ cargo build --target x86_64-pc-windows-gnu
   Compiling foobar v0.1.0 (/home/pfemidi/mywork/rust/foobar)
    Finished dev [unoptimized + debuginfo] target(s) in 4.46s
[pfemidi@pfemidi foobar]$

! ! .. wine, :


[pfemidi@pfemidi foobar]$ cargo run --target x86_64-pc-windows-gnu
    Finished dev [unoptimized + debuginfo] target(s) in 0.38s
     Running `target/x86_64-pc-windows-gnu/debug/foobar.exe`
Hello, world!
[pfemidi@pfemidi foobar]$

! 32bit Windows, run build:


error: linking with `i686-w64-mingw32-gcc` failed: exit code: 1

[...]

  = note: /usr/lib/gcc/i686-w64-mingw32/9.2.1/../../../../i686-w64-mingw32/bin/ld: /home/pfemidi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/crt2.o:crtexe.c:(.text+0x75): undefined reference to `__onexitend'
          /usr/lib/gcc/i686-w64-mingw32/9.2.1/../../../../i686-w64-mingw32/bin/ld: /home/pfemidi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/crt2.o:crtexe.c:(.text+0x7a): undefined reference to `__onexitbegin'
          collect2: error: ld returned 1 exit status

error: aborting due to previous error

error: could not compile `foobar`.

__onexitbegin __onexitend ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/crt2.o , , 64bit crt2.o dllcrt2.o , MinGW Fedora:


[pfemidi@pfemidi foobar]$ cd ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/
[pfemidi@pfemidi lib]$ cp /usr/i686-w64-mingw32/sys-root/mingw/lib/crt2.o .
[pfemidi@pfemidi lib]$ cp /usr/i686-w64-mingw32/sys-root/mingw/lib/dllcrt2.o .
[pfemidi@pfemidi lib]$ cd -
/home/pfemidi/mywork/rust/foobar
[pfemidi@pfemidi foobar]$ 

:


[pfemidi@pfemidi foobar]$ 
[pfemidi@pfemidi foobar]$ cargo run --target i686-pc-windows-gnu
   Compiling foobar v0.1.0 (/home/pfemidi/mywork/rust/foobar)
    Finished dev [unoptimized + debuginfo] target(s) in 5.12s
     Running `target/i686-pc-windows-gnu/debug/foobar.exe`
Hello, world!
[pfemidi@pfemidi foobar]$

.


, (macro panic!, expect ..) 32bit Windows. 64bit , 32bit .


:


[pfemidi@pfemidi foobar]$ cat src/main.rs 
fn main() {
    println!("Hello, world!");
    panic!("I'm panicked!");    //   !
}
[pfemidi@pfemidi foobar]

64bit Windows:


[pfemidi@pfemidi foobar]$ cargo run --target x86_64-pc-windows-gnu
   Compiling foobar v0.1.0 (/home/pfemidi/mywork/rust/foobar)
    Finished dev [unoptimized + debuginfo] target(s) in 2.95s
     Running `target/x86_64-pc-windows-gnu/debug/foobar.exe`
Hello, world!
thread 'main' panicked at 'I'm panicked!', src/main.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
[pfemidi@pfemidi foobar]$

, , . , 32bit Windows.


:


[pfemidi@pfemidi foobar]$ cargo run --target i686-pc-windows-gnu
   Compiling foobar v0.1.0 (/home/pfemidi/mywork/rust/foobar)
error: linking with `i686-w64-mingw32-gcc` failed: exit code: 1

[...]

  = note: /usr/lib/gcc/i686-w64-mingw32/9.2.1/../../../../i686-w64-mingw32/bin/ld: /home/pfemidi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/libpanic_unwind-1a1fb2d4d34efaf8.rlib(panic_unwind-1a1fb2d4d34efaf8.panic_unwind.2hbcqjo8-cgu.0.rcgu.o): in function `ZN12panic_unwind3imp5panic17hdaabfe6326236dacE':
          /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8\/src\libpanic_unwind/gcc.rs:73: undefined reference to `_Unwind_RaiseException'
          /usr/lib/gcc/i686-w64-mingw32/9.2.1/../../../../i686-w64-mingw32/bin/ld: /home/pfemidi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/libpanic_unwind-1a1fb2d4d34efaf8.rlib(panic_unwind-1a1fb2d4d34efaf8.panic_unwind.2hbcqjo8-cgu.0.rcgu.o): in function `rust_eh_unwind_resume':
          /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8\/src\libpanic_unwind/gcc.rs:327: undefined reference to `_Unwind_Resume'
          collect2: error: ld returned 1 exit status

error: aborting due to previous error

error: could not compile `foobar`.

, _Unwind_RaiseException _Unwind_Resume libpanic Rust.


, , Rust, . .


Rust Dwarf 32bit Windows SEH 64bit Windows, MinGW Fedora Linux SJLJ 32bit Windows SEH 64bit Windows ( ). 64bit , 32bit . MinGW Dwarf SJLJ 32bit Windows.


我不会详细介绍如何重新组装MinGW,它不是那么困难也不那么有趣(configure您需要使用一个参数来运行它--disable-sjlj-exceptions,其余的都是微不足道的),我只会说一件事:在MinGW展开堆栈后进行重建,Dwarf而不是SJLJ只需要一个名为libgcc_eh.a并出于目的将它放在库目录中i686-pc-windows-gnu之后,将开始收集使用紧急功能的项目,不仅用于64位Windows,还用于32位:


[pfemidi@pfemidi foobar]$ cd ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/i686-pc-windows-gnu/lib/
[pfemidi@pfemidi lib]$ cp ~/rpmbuild/BUILD/gcc-9.2.1-20190827/build_win32/i686-w64-mingw32/libgcc/libgcc_eh.a .
[pfemidi@pfemidi lib]$ cd -
/home/pfemidi/mywork/rust/foobar
[pfemidi@pfemidi foobar]$ cargo run --target i686-pc-windows-gnu
   Compiling foobar v0.1.0 (/home/pfemidi/mywork/rust/foobar)
    Finished dev [unoptimized + debuginfo] target(s) in 4.57s
     Running `target/i686-pc-windows-gnu/debug/foobar.exe`
Hello, world!
thread 'main' panicked at 'I'm panicked!', src/main.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
[pfemidi@pfemidi foobar]$ 

这样。


All Articles