Compilación cruzada Rust para ejecutables de Windows desde Linux

Probablemente no sea muy sorprendente si estoy aquí, en el sitio de Habr IT, diré que a veces me mimo con la programación.


Mi sistema operativo principal es Linux, pero a veces también tengo que recopilar archivos ejecutables para Windows. Y, por supuesto, no quiero reiniciar Windows solo para el ensamblaje exe. No hay problemas con los lenguajes C y C ++, durante mucho tiempo hay un compilador cruzado MinGWque lo hace muy bien. Sobre Pythone Javaincluso no vale la pena mencionar, multiplataforma en ellos inicialmente. Pero el año pasado decidí probar un lenguaje tan novedoso como Rust. Al ensamblar el archivo ejecutable utilizando el administrador de paquetes incluido en el kit de distribución de Rust, cargoparece ser suficiente especificar una clave --targetcon la que especificar el procesador resultante, la arquitectura y la ABI y, al compilar desde Linux, obtener exe, que será el archivo ejecutable estándar para Windows. Pero tratando de hacerlo:


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

Solo recibí mensajes de error del enlazador:


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`.

Si alguien está interesado en cómo superé esto y ahora puedo compilar fácilmente programas Rust para Windows sin salir de Linux, bienvenido a cat.


Descargo de responsabilidad

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


En primer lugar, nos aseguramos de haber establecido los objetivos necesarios ejecutando el siguiente comando:


rustup target list

Obtenemos una lista de todos los objetivos posibles y los objetivos que hemos establecido:


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)
[...]

Para crear archivos ejecutables para Windows desde Linux, necesitamos objetivos i686-pc-windows-gnupara 32bit exe y x86_64-pc-windows-gnu64bit exe. Si estos objetivos no están marcados como (installed), los entregamos utilizando el comando


rustup target add _

Después de asegurarnos de que tenemos un compilador cruzado instalado MinGWejecutando


rpm -qa | grep mingw

u otro administrador de paquetes para nuestra distribución de 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

Si no, MinGWinstale los paquetes necesarios ejecutando


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.


No voy a entrar en detalles sobre cómo volver a armar MinGW, no es tan difícil ni tan interesante ( configuredebe ejecutarlo con un parámetro --disable-sjlj-exceptions, el resto es trivial), solo diré una cosa: después de MinGWreconstruir con el desbobinado de la pila, en Dwarflugar de SJLJeso, debe tomar solo un archivo llamado libgcc_eh.ay ponerlo en el directorio de la biblioteca para tal fin i686-pc-windows-gnu. Después de eso, los proyectos en los que se utilizan funciones de pánico comenzarán a recopilarse no solo para Windows de 64 bits, sino también para 32 bits:


[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]$ 

De alguna manera como esta.


All Articles