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

e4yzc0pl  于 2022-11-30  发布在  其他
关注(0)|答案(7)|浏览(961)

刚找到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命令(在发布版本中的调试信息?)?还有什么其他的可以让我们了解发生了什么?

oo7oh9g9

oo7oh9g91#

Rust使用静态链接来编译它的程序,这意味着即使是最简单的Hello world!程序所需的所有库都将被编译到你的可执行文件中,这也包括Rust运行时。
要强制Rust动态链接程序,请使用命令行参数-C prefer-dynamic;这将导致一个小得多的文件大小***但是***也将要求Rust库(包括它的运行时)在运行时对你的程序可用。2这实质上意味着如果计算机没有它们,你将需要提供它们,占用比你原来的静态链接程序所占用的 * 更多 * 的空间。
为了便于移植,我建议您静态链接Rust库和运行时,如果您要将程序分发给其他人,请使用您一直使用的方式。

0ve6wy6x

0ve6wy6x2#

默认情况下,Rust编译器针对执行速度、编译速度和调试的简易性(例如,通过包括符号)进行优化,而不是针对最小二进制大小进行优化。
要了解减少Rust二进制文件大小的所有方法,请参阅我的min-sized-rust GitHub仓库。
当前减少二进制大小的高级步骤包括:
1.使用Rust 1.32.0或更高版本(默认情况下不包括jemalloc
1.将以下内容添加到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 = true需要Rust 1.59+。在较旧的Rust版本上,对生成的二进制文件手动运行strip

1.使用cargo build --release在发布模式中生成
使用nightly Rust可以做更多的事情,但是我将把这些信息留在min-sized-rust中,因为它会随着时间的推移而变化,这是由于使用了不稳定的特性。
您也可以使用#![no_std]来移除Rust的libstd。请参阅min-sized-rust以取得详细信息。

dfddblmv

dfddblmv3#

我没有任何Windows系统可以尝试,但是在Linux上,静态编译的Rust hello world实际上比等效的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(d17 d 6 e7 f1 2015-04-02)(2015 -04-03)编译的,都有默认选项,gcc的-static和rustc的-C prefer-dynamic
我有两个版本的C hello world,因为我认为使用puts()可能会在更少的编译单元中链接。
如果你想尝试在Windows上复制它,这里是我使用的来源:
打印文件c:

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

看跌期权。c:

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

rust.rs

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

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

b1zrtrql

b1zrtrql4#

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

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

这将大大减少二进制文件的大小,因为它现在是动态链接的。
至少在Linux上,您还可以使用strip命令剥离二进制文件中的符号:

strip target/release/<binary>

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

dced5bon

dced5bon5#

安装
现在,在项目的所有Cargo.toml文件中进行这些更改。
在Cargo.toml顶部的[package]之前添加cargo-features = ["strip"]
在底部,或在[dependencies][package]之间添加、

[profile.release]
# strip = true  # Automatically strip symbols from the binary.
opt-level = "z"  # Optimize for size.
lto = true  # Enable link time optimization
codegen-units = 1  # Reduce parallel code generation units

现在使用RUSTFLAGS='-C link-arg=-s' cargo build --release构建
我发现这些链接很有用- * https://collabora.com/news-and-blog/blog/2020/04/28/reducing-size-rust-gstreamer-plugin/ * 和 * https://github.com/johnthagen/min-sized-rust * 和 * https://arusahni.net/blog/2020/03/optimizing-rust-binary-size.html *

lokaqttq

lokaqttq6#

可执行文件可能很大的原因之一是由于Rust编译器处理泛型的方式。Rust不使用多态性,而是使用monomorphization。这意味着编译器为每个具体类型的每个泛型函数创建一个单独的代码副本(根据需要)。The dev guide outlines it here
例如,如果我使用Vec这样的泛型类型,并且在我的代码中有几个Vec<i32>Vec<bool>Vec<String>这样的示例,那么编译器将为上述泛型生成3个独立的代码副本。一个用于Vec<i32>,一个用于Vec<bool>,等等...
这种方法的缺点之一是编译时间增加,二进制文件更大。从好的方面来说,编译后的代码应该运行得更快,因为在运行时不需要推断任何东西,而且每个具体类型都有(应该有?)一个针对该具体类型的优化实现。

uz75evzq

uz75evzq7#

这是一个功能,而不是一个错误!
您可以指定程序中使用的库版本(在project's associated Cargo.toml file中)(甚至是隐式版本)以确保库版本兼容性。另一方面,这要求特定的库静态链接到可执行文件,从而生成大型运行时映像。
嘿,现在已经不是1978年了--很多人的电脑内存都超过了2 MB:-)

相关问题