为什么Rust可执行文件如此庞大?

时间:2015-03-12 11:07:46

标签: rust rust-cargo

刚刚找到Rust并阅读了文档的前两章,我发现他们定义语言的方法和方式特别有趣。所以我决定让我的手指湿透,开始使用Hello world ...

我是在Windows 7 x64上完成的,顺便说一句。

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

发布cargo build并在targets\debug中查看结果,我发现结果.exe为3MB。经过一些搜索(很难找到货物命令行标志的文档......),我找到了--release选项并创建了发布版本。令我惊讶的是,.exe大小只变小了一小部分:2.99MB而不是3MB。

所以,承认我是Rust及其生态系统的新手,我的期望是系统编程语言会产生紧凑的东西。

任何人都可以详细说明Rust正在编译的内容,如何通过3个班轮程序生成如此巨大的图像?它是否正在编译为虚拟机?我错过了一个strip命令(在发布版本中调试信息吗?)?还有什么可能让我们了解发生了什么?

6 个答案:

答案 0 :(得分:102)

Rust使用静态链接来编译程序,这意味着即使是最简单的Hello world!程序所需的所有库也将被编译到您的可执行文件中。这还包括Rust运行时。

要强制Rust动态链接程序,请使用命令行参数-C prefer-dynamic;这将导致文件小得多 ,但 还需要Rust库(包括其运行时)在运行时可供您的程序使用。 这实际上意味着如果计算机没有它们,您将需要提供它们,占用更多空间,而不是原始静态链接程序占用的空间。

为了便于携带,我建议您按照自己的方式静态链接Rust库和运行时,如果您要将程序分发给其他人。

答案 1 :(得分:49)

我没有任何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)编译的,两者都有默认选项和{ {1}}用于gcc,-static用于rustc。

我有两个版本的C hello世界因为我认为使用-C prefer-dynamic可能会链接更少的编译单元。

如果您想尝试在Windows上复制它,以下是我使用的来源:

printf.c:

puts()

puts.c:

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

rust.rs

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

另外,请记住,不同数量的调试信息或不同的优化级别也会产生影响。但我希望如果你看到一个巨大的差异,那是由于静态与动态链接。

答案 2 :(得分:21)

使用Cargo进行编译时,您可以使用动态链接:

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

这将大大减小二进制文件的大小,因为它现在是动态链接的。

至少在Linux上,您还可以使用strip命令删除符号二进制文件:

strip target/release/<binary>

这大约会使大多数二进制文件的大小减半。

答案 3 :(得分:7)

有关减少Rust二进制文件大小的所有方法的概述,请参见min-sized-rust存储库。

当前减小二进制文件大小的高级步骤是:

  1. 使用Rust 1.32.0或更高版本(默认情况下不包括jemalloc
  2. 将以下内容添加到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. 使用cargo build --release
  2. 以发布模式构建
  3. 在生成的二进制文件上运行strip

使用nightly Rust可以完成更多工作,但是由于使用了不稳定的功能,信息会随着时间的推移而变化,因此我会将这些信息留在min-sized-rust中。

您还可以使用#![no_std]删除Rust的libstd。有关详细信息,请参见min-sized-rust

答案 4 :(得分:-1)

如果您使用“ rustc”命令进行编译,只需编写命令“ rustc -C preferred-dynamic = yes main.rs”

答案 5 :(得分:-4)

这是一个功能,而不是一个错误!

您可以指定程序中使用的库版本(在project's associated Cargo.toml file中)(甚至是隐式版本)以确保库版本兼容性。另一方面,这需要将特定库静态链接到可执行文件,从而生成大的运行时映像。

嘿,它不再是1978年了 - 很多人的电脑中有超过2 MB的RAM: - )