Подтвердить что ты не робот

Почему Rust исполняемые файлы настолько огромны?

Просто обнаружив Rust и прочитав первые две главы документации, я нахожу подход и то, как они определили язык, особенно интересный. Поэтому я решил намочить мои пальцы и начать с Hello world...

Я сделал это на Windows 7 x64, btw.

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

Выдавая cargo build и глядя на результат в targets\debug, я обнаружил, что полученный .exe составляет 3 МБ. После некоторых поисков (документация по флагам командной строки груза трудно найти...) Я нашел параметр --release и создал сборку выпуска. К моему удивлению, размер .exe уменьшился лишь незначительно: 2,99 МБ вместо 3 МБ.

Итак, признавшись, что я новичок в Rust и его экосистеме, я ожидал, что язык системного программирования создаст что-то компактное.

Может ли кто-нибудь уточнить, что компилирует Rust, как это возможно, он создает такие огромные изображения из 3-х линейных программ? Собирает ли она виртуальную машину? Есть ли какая-либо команда, которую я пропустил (отладочная информация внутри сборки релиза?)? Что-нибудь еще, что могло бы понять, что происходит?

4b9b3361

Ответ 1

Rust использует статическое связывание для компиляции своих программ, что означает, что все библиотеки, необходимые даже самой простой программе Hello world!, будут скомпилированы в ваш исполняемый файл. Это также включает время выполнения Rust.

Чтобы заставить Rust динамически связывать программы, используйте аргументы командной строки -C prefer-dynamic; это приведет к значительно меньшему размеру файла , но также потребует, чтобы библиотеки Rust (включая их время выполнения) были доступны вашей программе во время выполнения. Это по существу означает, что вам нужно будет предоставить их, если компьютер их не имеет, занимая больше места, чем ваша исходная статически связанная программа.

Для портативности я бы рекомендовал вам статически связывать библиотеки Rust и время выполнения так, как вы делали, если бы вы когда-либо распространяли ваши программы на других.

Ответ 2

У меня нет каких-либо систем Windows, чтобы попробовать, но в Linux статически скомпилированный мир rust hello на самом деле меньше, чем эквивалент C. Если вы видите огромную разницу в размере, это, вероятно, связано с тем, что вы связываете Rust исполняемый статически и C один динамически.

С динамической компоновкой вам нужно также учитывать размер всех динамических библиотек, а не только исполняемый файл.

Итак, если вы хотите сравнить яблоки с яблоками, вам нужно убедиться, что оба они являются динамическими или оба являются статическими. У разных компиляторов будут разные значения по умолчанию, поэтому вы не можете просто полагаться на значения по умолчанию для компилятора, чтобы получить тот же результат.

Если вам интересно, вот мои результаты:

-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

Они были скомпилированы с gcc (Debian 4.9.2-10) 4.9.2 и rustc 1.0.0-nightly (d17d6e7f1 2015-04-02) (построено в 2015-04-03), как с параметрами по умолчанию, так и с -static для gcc и -C prefer-dynamic для rustc.

У меня было две версии C hello world, потому что я думал, что использование puts() может связываться с меньшим количеством единиц компиляции.

Если вы хотите попробовать воспроизвести его в Windows, вот те источники, которые я использовал:

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!");
}

Кроме того, имейте в виду, что разные объемы отладочной информации или разные уровни оптимизации также будут иметь значение. Но я ожидаю, что если вы увидите огромную разницу, это связано со статической или динамической привязкой.

Ответ 3

При компиляции с Cargo вы можете использовать динамическое связывание:

cargo rustc --release -- -C prefer-dynamic

Это значительно уменьшит размер двоичного файла, так как теперь он динамически связан.

В Linux, по крайней мере, вы также можете разбить двоичный код символов командой strip:

strip target/release/<binary>

Это примерно вдвое увеличит размер большинства двоичных файлов.