¿Por qué los ejecutables de Rust son tan grandes?

Resuelto BitTickler asked hace 9 años • 7 respuestas

Encuentro particularmente interesante el enfoque y la forma en que definen el lenguaje en los dos primeros capítulos de la documentación. Así que decidí mojarme los dedos y comencé con "¡Hola mundo!".

Lo hice en Windows 7 x64, por cierto.

fn main() {
    println!("Hello, world!");
}

Al emitir cargo buildy observar el resultado, targets\debugencontré que el resultado .exeera 3 MB. Después de algunas búsquedas (la documentación de los indicadores de la línea de comando de carga es difícil de encontrar...) encontré la --releaseopción y creé la versión de lanzamiento. Para mi sorpresa, el tamaño del .exe sólo se ha reducido en una cantidad insignificante: 2,99 MB en lugar de 3 MB.

Mi expectativa habría sido que un lenguaje de programación de sistemas produciría algo compacto.

¿Alguien puede explicar en qué se está compilando Rust y cómo es posible que produzca imágenes tan grandes a partir de un programa de 3 líneas? ¿Se está compilando en una máquina virtual? ¿Hay algún comando de extracción que me perdí (¿información de depuración dentro de la versión de lanzamiento?)? ¿Algo más que pueda permitir entender lo que está pasando?

BitTickler avatar Mar 12 '15 18:03 BitTickler
Aceptado

De forma predeterminada, el compilador de Rust optimiza la velocidad de ejecución, la velocidad de compilación y la facilidad de depuración (al incluir símbolos, por ejemplo), en lugar de un tamaño binario mínimo.

Para obtener una descripción general de todas las formas de reducir el tamaño de un binario de Rust, consulte mi min-sized-rustrepositorio de GitHub.

Los pasos actuales de alto nivel para reducir el tamaño binario son:

  1. Utilice Rust 1.32.0 o posterior (que no se incluye jemallocde forma predeterminada)
  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
strip = true        # Strip symbols from binary*

* strip = truerequiere Rust 1.59+. En versiones anteriores de Rust, ejecútelo stripmanualmente en el binario resultante.

  1. Construir en modo de lanzamiento usandocargo build --release

Se puede hacer más con nightlyRust, pero dejaré esa información ya min-sized-rustque cambia con el tiempo debido al uso de funciones inestables.

También puedes usarlo #![no_std]para eliminar Rust's libstd. Ver min-sized-rustpara más detalles.

johnthagen avatar Feb 23 '2019 13:02 johnthagen

Rust utiliza enlaces estáticos para compilar sus programas, lo que significa que todas las bibliotecas requeridas incluso por el Hello world!programa más simple se compilarán en su ejecutable. Esto también incluye el tiempo de ejecución de Rust.

Para obligar a Rust a vincular programas dinámicamente, utilice 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 de Rust (incluido su tiempo de ejecución) estén disponibles para su programa en tiempo de ejecución. Básicamente, esto significa que deberá proporcionarlos si la computadora no los tiene, lo que ocupará más espacio del que ocupa su programa original vinculado estáticamente.

Para la portabilidad, le recomendaría que vincule estáticamente las bibliotecas de Rust y el tiempo de ejecución de la forma en que lo ha estado haciendo si alguna vez distribuyera sus programas a otros.

AStopher avatar Mar 12 '2015 11:03 AStopher

No tengo ningún sistema Windows para probar, pero en Linux, un Hola mundo de Rust compilado estáticamente es en realidad más pequeño que el C equivalente. Si ve una gran diferencia en tamaño, probablemente se deba a que está vinculando el ejecutable de Rust. estáticamente y el C de forma dinámica.

Con los enlaces dinámicos, también debes 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 estáticas. Diferentes compiladores tendrán diferentes valores predeterminados, por lo que no puede confiar simplemente 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 5 de abril 14:26 printf.c
-rwxr-xr-x 1 aij aij 6696 5 de abril 14:27 printf.dyn
-rwxr-xr-x 1 aij aij 829344 5 de abril 14:27 printf.static
-rw-r--r-- 1 aij aij 59 5 abr 14:26 puts.c
-rwxr-xr-x 1 aij aij 6696 5 de abril 14:27 puts.dyn
-rwxr-xr-x 1 aij aij 829344 5 de abril 14:27 puts.static
-rwxr-xr-x 1 aij aij 8712 5 de abril 14:28 Rust.dyn
-rw-r--r-- 1 aij aij 46 5 de abril 14:09 Rust.rs
-rwxr-xr-x 1 aij aij 661496 5 de abril 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) (compilado el 2015-04-03), ambos con opciones predeterminadas y con -staticfor gcc y -C prefer-dynamicfor oxidado.

Tenía dos versiones de C hola mundo porque pensé que usarlo puts()podría vincularse en menos unidades de compilación.

Si quieres intentar reproducirlo en Windows, aquí están las fuentes que utilicé:

printf.c:

#include <stdio.h>
int main() {
  printf("Hello, world!\n");
}

pone.c:

#include <stdio.h>
int main() {
  puts("Hello, world!");
}

óxido.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 ve una gran diferencia se deba a los enlaces estáticos versus dinámicos.

aij avatar Apr 05 '2015 19:04 aij