rust rust-cargo

¿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:

  1. Use Rust 1.32.0 o más reciente (que no incluye jemalloc por defecto)
  2. 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

  1. Construir en modo de lanzamiento usando cargo build --release
  2. 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.