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 MinGW
que lo hace muy bien. Sobre Python
e Java
incluso 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, cargo
parece ser suficiente especificar una clave --target
con 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 responsabilidad32bit 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-gnu
para 32bit exe y x86_64-pc-windows-gnu
64bit 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 MinGW
ejecutando
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, MinGW
instale 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 ( configure
debe ejecutarlo con un parámetro --disable-sjlj-exceptions
, el resto es trivial), solo diré una cosa: después de MinGW
reconstruir con el desbobinado de la pila, en Dwarf
lugar de SJLJ
eso, debe tomar solo un archivo llamado libgcc_eh.a
y 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.