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


153

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

我是在Windows 7 x64,btw上执行的。

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

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

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

谁能详细说明Rust编译的内容,如何通过3线性程序生成如此大的图像?它可以编译到虚拟机吗?我是否错过了一个剥离命令(在发行版内部调试信息?)?还有什么可能让您了解正在发生的事情吗?


4
我认为3Mb不仅包含Hello World,还包含该平台所需的所有环境。使用Qt可以看到相同的结果。这并不意味着如果编写6行程序,大小将变为6 Mb。它将保持在3Mb,之后将非常缓慢地增长。
安德烈·尼古拉连科

8
@AndreiNikolaenko我知道这一点。但这暗示它们要么不像C那样处理库,要么仅向图像添加所需的内容,否则其他事情正在发生。
BitTickler 2015年

@ user2225104请参阅我的答案,RUST以与C相同(或相似)的方式处理库,但是默认情况下C不会将静态库编译到您的程序中(至少在C ++上)。
AStopher


1
现在过时了吗?使用rustc版本1.35.0并且没有cli选项,我得到的文件大小为137kb。它是现在自动自动动态链接编译还是在此期间发生了其他事情?
itmuckel

Answers:


139

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

要强制Rust动态链接程序,请使用命令行参数-C prefer-dynamic; 这将导致文件大小更小,同时要求Rust库(包括其运行时)在运行时可用于您的程序。这实质上意味着,如果计算机没有它们,则将需要提供它们,与原始静态链接程序所占用的空间相比,它们会占用更多的空间。

为了可移植性,如果您要将程序分发给其他人,我建议您以您一直使用的方式静态链接Rust库和运行时。


4
@ user2225104不确定Cargo,但是根据GitHub上的此错误报告,不幸的是这还不可能。
AStopher

2
但是,一旦系统上有2个以上的rust可执行文件,动态链接就会开始为您节省空间…
binki 2016年

15
我认为静态链接无法解释庞大的HELLO-WORLD。它不应该仅链接到实际使用的库的各个部分,而HELLO-WORLD实际上不使用任何内容吗?
MaxB

8
BitTicklercargo rustc [--debug or --release] -- -C prefer-dynamic
Zach Mertes

3
@daboross非常感谢。我一直在跟踪这个相关的RFC。真可惜,因为Rust还针对系统编程。
富兰克林·于

62

我没有任何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 4月5日14:27 printf.dyn
-rwxr-xr-x 1 aij aij 829344 4月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 4月5日14:27 puts.static
-rwxr-xr-x 1 aij aij 8712 4月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 4月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-dynamicfor锈

我有两个版本的C hello世界,因为我认为使用puts()可能会链接较少的编译单元。

如果要尝试在Windows上重现它,请使用以下来源:

printf.c:

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

puts.c:

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

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

另外,请记住,不同数量的调试信息或不同的优化级别也会有所不同。但是我希望,如果您看到巨大的差异,这是由于静态链接与动态链接引起的。


27
gcc非常聪明,可以精确地执行printf->放置替换本身,这就是为什么结果相同的原因。
2015年

6
从2018年开始,如果您想进行公平的比较,请记住要``剥离''这些可执行文件,因为我的系统上的世界Rust可执行文件高达5.3MB,但是在删除所有调试符号时降至不到10%。这样。
Matti Virkkunen '18

@MattiVirkkunen:2020年仍然如此;自然的大小看起来更小(接近5.3M),但是符号与代码的比率仍然非常高。在CentOS 7上,Rust 1.34.0上的调试构建(纯默认选项)strip -s从1.6M降至190K,剥去了。发布版本(默认为+ opt-level='s'lto = true和,panic = 'abort'以减小大小)从623K降至158K。
ShadowRanger

如何区分静态和动态苹果?后者听起来不健康。
LF

30

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

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

由于它现在是动态链接的,因此将大大减少二进制文件的大小。

至少在Linux上,您还可以使用以下strip命令剥离符号的二进制文件:

strip target/release/<binary>

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


8
某些统计信息,您好世界的默认发行版本(linux x86_64)。3.5 M,动力首选8904 B,剥离
6392B。– Zitrax

30

有关减少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. strip在生成的二进制文件上运行。

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

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


-10

这是功能,不是错误!

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

嘿,现在不再是1978年-许多人的计算机中的RAM超过2 MB :-)


9
指定库的版本需要静态链接特定的库 —不,不是。动态链接库的确切版本时,存在大量代码。
Shepmaster '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.