¿Por qué los ejecutables de Rust son tan grandes?
rust install dependencies (5)
Solo por haber encontrado a Rust y haber leído los dos primeros capítulos de la documentación, encuentro el enfoque y la forma en que definieron el lenguaje particularmente interesante. Así que decidí mojarme los dedos y comencé con Hello world ...
Lo hice en Windows 7 x64, por cierto.
fn main() {
println!("Hello, world!");
}
Emitiendo la
cargo build
y mirando el resultado en
targets/debug
, encontré que el
.exe
resultante es de 3 MB.
Después de algunas búsquedas (la documentación de las banderas de la línea de comando de carga es difícil de encontrar ...)
--release
opción de liberación y creé la versión de lanzamiento.
Para mi sorpresa, el tamaño .exe solo se ha reducido en una cantidad insignificante: 2.99MB en lugar de 3MB.
Entonces, confesando que soy un novato en Rust y su ecosistema, mi expectativa hubiera sido que un lenguaje de Programación de Sistemas produciría algo compacto.
¿Alguien puede dar más detalles sobre lo que está compilando Rust, cómo puede ser posible que produzca imágenes tan grandes de un programa de 3 líneas? ¿Se está compilando en una máquina virtual? ¿Hay un comando de strip que me perdí (información de depuración dentro de la compilación de lanzamiento)? ¿Algo más que pueda permitir entender lo que está pasando?
¡Esto es una característica, no un error!
Puede especificar las versiones de la biblioteca (en el archivo Cargo.toml asociado al proyecto ) utilizadas en el programa (incluso las implícitas) para garantizar la compatibilidad de la versión de la biblioteca. Esto, por otro lado, requiere que la biblioteca específica esté vinculada estáticamente al ejecutable, generando grandes imágenes en tiempo de ejecución.
Hola, ya no es 1978, muchas personas tienen más de 2 MB de RAM en sus computadoras :-)
Al compilar con Cargo, puede usar la vinculación dinámica:
cargo rustc --release -- -C prefer-dynamic
Esto reducirá drásticamente el tamaño del binario, ya que ahora está vinculado dinámicamente.
En Linux, al menos, también puede quitar el binario de los símbolos con el comando
strip
:
strip target/release/<binary>
Esto reducirá aproximadamente a la mitad el tamaño de la mayoría de los binarios.
No tengo ningún sistema Windows para probar, pero en Linux, un mundo de Rust hello compilado estáticamente es en realidad más pequeño que el equivalente C. Si está viendo una gran diferencia de tamaño, probablemente sea porque está vinculando el ejecutable de Rust estáticamente y el C dinámicamente.
Con el enlace dinámico, también debe tener en cuenta el tamaño de todas las bibliotecas dinámicas, no solo el ejecutable.
Por lo tanto, si desea comparar manzanas con manzanas, debe asegurarse de que ambas sean dinámicas o ambas sean estáticas. Los diferentes compiladores tendrán valores predeterminados diferentes, por lo que no puede confiar solo en los valores predeterminados del compilador para producir el mismo resultado.
Si estás interesado, aquí están mis resultados:
-rw-r--r-- 1 aij aij 63 Apr 5 14:26 printf.c -rwxr-xr-x 1 aij aij 6696 Apr 5 14:27 printf.dyn -rwxr-xr-x 1 aij aij 829344 Apr 5 14:27 printf.static -rw-r--r-- 1 aij aij 59 Apr 5 14:26 puts.c -rwxr-xr-x 1 aij aij 6696 Apr 5 14:27 puts.dyn -rwxr-xr-x 1 aij aij 829344 Apr 5 14:27 puts.static -rwxr-xr-x 1 aij aij 8712 Apr 5 14:28 rust.dyn -rw-r--r-- 1 aij aij 46 Apr 5 14:09 rust.rs -rwxr-xr-x 1 aij aij 661496 Apr 5 14:28 rust.static
Estos fueron compilados con gcc (Debian 4.9.2-10) 4.9.2 y rustc 1.0.0-nightly (d17d6e7f1 2015-04-02) (construido 2015-04-03), ambos con opciones predeterminadas y con
-static
para gcc y
-C prefer-dynamic
para rustc.
Tenía dos versiones del mundo C hello porque pensé que usar
puts()
podría enlazar en menos unidades de compilación.
Si quieres intentar reproducirlo en Windows, estas son las fuentes que utilicé:
printf.c:
#include <stdio.h>
int main() {
printf("Hello, world!/n");
}
puts.c:
#include <stdio.h>
int main() {
puts("Hello, world!");
}
rust.rs
fn main() {
println!("Hello, world!");
}
Además, tenga en cuenta que diferentes cantidades de información de depuración o diferentes niveles de optimización también marcarían la diferencia. Pero espero que si está viendo una gran diferencia, se debe a la vinculación estática frente a la dinámica.
Para obtener una descripción general de todas las formas de reducir el tamaño de un binario Rust, consulte el repositorio de
min-sized-rust
.
Los pasos actuales de alto nivel para reducir el tamaño binario son:
-
Use Rust 1.32.0 o más reciente (que no incluye
jemalloc
por defecto) -
Agregue lo siguiente a
Cargo.toml
[profile.release]
opt-level = ''z'' # Optimize for size.
lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
panic = ''abort'' # Abort on panic
-
Construir en modo de lanzamiento usando
cargo build --release
-
Ejecute
strip
en el binario resultante.
Hay más que se puede hacer usando Rust
nightly
, pero dejaré esa información en
min-sized-rust
ya que cambia con el tiempo debido al uso de características inestables.
También puede usar
#![no_std]
para eliminar la
libstd
de Rust.
Vea el
min-sized-rust
de
min-sized-rust
para más detalles.
Rust utiliza enlaces estáticos para compilar sus programas, lo que significa que todas las bibliotecas son necesarias incluso para el
Hello world!
más simple de
Hello world!
El programa se compilará en su ejecutable.
Esto también incluye el tiempo de ejecución de Rust.
Para forzar a Rust a vincular dinámicamente programas, use los argumentos de la línea de comandos
-C prefer-dynamic
;
esto dará como resultado un tamaño de archivo mucho más pequeño,
pero
también requerirá que las bibliotecas Rust (incluido su tiempo de ejecución) estén disponibles para su programa en tiempo de ejecución.
Esto significa esencialmente que deberá proporcionarlos si la computadora no los tiene, ocupando
más
espacio del que ocupa su programa original vinculado estáticamente.
Para la portabilidad, le recomiendo que enlace estáticamente las bibliotecas Rust y el tiempo de ejecución de la forma en que lo ha estado haciendo si alguna vez distribuyera sus programas a otros.