查看原文
其他

【Rust 漫画】揭开 Hello World 二进制文件巨大之谜

张汉东 觉学社 2023-10-15

前言

创意:张汉东 绘画:ChatGPT DALL•E3

创意来源:本人学习 Rust 过程中的一些踩坑、成长与思考。

如果大家喜欢,欢迎点赞、转发和赞赏,每一位读者对认可是我持续创作的动力。

漫画赏析


漫画解析

当 Rust 新人写下第一个 Hello World 程序时:

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

在编译以后,看了二进制文件大小,多半会非常惊讶!你可能看到二进制文件大小高达 4 MB ,而 cpp 的 Hello world 二进制文件才 170kb,相比之下,Rust 二进制文件大小就太大了。

在 2015 年 Rust 1.0 发布之后的两三年内,这个问题曾在社区中引起了很大争议。

为什么 hello world 二进制文件如此巨大?

Rust语言在默认情况下产生较大的“Hello, World!”二进制文件的原因主要与其编译和链接策略有关。

  1. 静态链接
  • 默认情况下,Rust 产生的二进制是静态链接的,这意味着所有用到的库和函数都被直接包含在生成的文件中,而不是在运行时动态地加载。
  • 这一策略有其好处:生成的二进制文件在不同的系统上更具有独立性和可移植性,因为它不依赖于外部的库文件。但这也导致了较大的文件大小。
  • 即便是最简单的Rust程序,也会链接到Rust的标准库,也被称为std。这个库提供了许多基础的功能,如IO操作、线程管理、数据结构等。
  • 这些功能虽然在“Hello, World!”程序中可能未直接使用,但它们被包括在了编译的输出中。

其实 Rust的编译器(特别是其链接器)实际上是智能的,并采用了一个称为“树摇(tree shaking)”或“死代码消除(dead code elimination)”的过程,让它只会链接那些你的程序真正用到的库代码部分。

死代码消除:

  • Rust编译器会分析代码,确定哪些函数、变量和其他结构是未使用的。在编译和链接的过程中,所有未使用的代码(死代码)都不会出现在最终的二进制文件中。
  • Rust的标准库是模块化的。当你使用某个特定的模块或功能时,只有那部分代码会被拉入最终的二进制。例如,如果你的代码从标准库中只使用了 Vecprintln!,那么只有与这些功能相关的代码部分会被包括进来。
  • 静态链接的影响:尽管 Rust 进行了死代码消除,但静态链接仍然可能会导致较大的二进制文件,因为所有必要的代码都被包含在单个文件中。这与动态链接相反,其中二进制文件依赖于外部的共享库。
  • 其他因素:除了标准库和你的代码,还有其他因素可能影响编译输出的大小,例如调试信息、优化等级等。

那么该如何优化编译大小呢?

  1. 发布模式:通过使用cargo build --release,你可以告诉Rust进行更多的优化,并去除调试信息。这通常会显著减小生成的二进制文件大小。

  2. 去除标准库:对于某些特定应用,如嵌入式系统编程,你可能不需要整个标准库。在这种情况下,你可以考虑使用#![no_std]属性来禁用标准库。

  3. 使用strip命令strip是一个可以移除二进制文件中符号信息的工具,进一步减小文件大小。

  4. 其他优化工具和策略:例如,使用upx可以进一步压缩生成的二进制文件。还有其他的Cargo插件和工具,如cargo-bloat,可以帮助你识别和减小二进制文件大小。

社区也有人总结了如何优化编译文件大小:min-sized-rust[1]

其中也提供了一些优化配置:

[package]
name = "min-sized-rust"
version = "0.1.0"
authors = ["johnthagen <johnthagen@gmail.com>"]
license-file = "LICENSE.txt"

[dependencies]

[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 # Automatically strip symbols from the binary.

最终效果还是可以的。

后记

Rust 编译时间、编译文件大小和性能优化,也一个不可能三角,需要根据实际情况和需求进行权衡。

参考资料

[1]

min-sized-rust: https://github.com/johnthagen/min-sized-rust


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存