前言
在路由器上运行 go
和 rust
编译的程序时, 发现可执行文件的大小较大, 便思考如何缩小其大小
Gopher
ldflags
1 | $ go build -ldflags '-w -s' |
-w
禁止生成debug信息,注意使用该选项后,无法使用 gdb 进行调试
-s
禁止符号信息
可以使用 go tool link –help 查看 ldflags 各参数含义
gcflags
1 | $ go build -gcflags '-N -l' |
-N
禁止编译优化
-l
禁止内联,禁止内联也可以一定程度上减小可执行程序大小
可以使用 go tool compile –help 查看 gcflags 各参数含义
Rustacean
release
1 | $ cargo build --release |
使用 release
编译而不是 dev
opt-level
1 | [profile.release] |
默认的 release 优化等级为 3,这个等级下编译器会进行循环展开之类的操作以体积膨胀为代价提高程序运行速度
不过这次我们在优化体积,我们不需要以体积为代价的优化。因为我们调整优化等级为 z
,意为最小二进制体积
lto
1 | [profile.release] |
LTO(Link Time Optimization),意为链接时优化。可以消除大量冗余代码,减小二进制体积——代价是更长的链接时间
codegen-units
1 | [profile.release] |
Cargo 默认会启用 16 个并行代码生成单元,对编译速度有提升,但是会妨碍某些优化的进行。我们限制到 1
panic
1 | [profile.release] |
众所周知,Rust 程序在 panic 时会生成栈回溯,方便定位问题。而这个 flag 会禁用这种行为——请自行权衡使用
1 | [dependencies] |
即使已经在 Cargo.toml
指定了 panic = 'abort'
,rustc
默认还是会生成相关的格式化字符串。我们可以通过 feature panic_immediate_abort
来禁止这个行为
libstd
Rust 的工具链自带了预编译的标准库(libstd),这样开发者就不用在每次编译 Rust 程序的时候都编译一遍 libstd,而是直接把 libstd 静态链接进去就行。
好处是很明显的,然而坏处也是很明显的:
预编译的 libstd 着重优化速度而不是体积
即使是 LTO 也无法移除 libstd 中的某些我们用不到的代码
这时就轮到 Xargo 出场了——一个可以方便地为你的程序单独编译 libstd 的工具。
在项目根目录下创建 Xargo.toml(不需要删掉原来的 Cargo.toml),写入:
1 | [dependencies] |
然后编译(target 请自行调整)
1 | $ xargo build --target x86_64-unknown-linux-gnu --release |
Common
strip
1 | $ strip -s binary |
最基本的优化体积方式,可以去除(对正常运行)无用的符号信息
在 go
当中等同于
1 | $ go build -ldflags '-s' |
在 rust
当中可以通过修改 Cargo.toml
实现
目前仅支持
nghitly
版本
1 | cargo-features = ["strip"] |
upx
1 | $ upx -9 binary |
实测可以压缩很多空间, 但在 mips
之类的平台似乎会无法运行