1. 前言
本文讨论使用 GoReleaser 优化二进制产物的体积。
通常直接使用
go build
构建出来的二进制包含了符号表和调试信息,所以体积会比较大,比如我之前写的一个 CLI 工具 mdfmt 在优化之前的二进制体积为 20M。优化之后,体积变为了 4.7M,体积降低了 76.5%:
2. 优化方案
2.1 编译参数
Go 编译器默认编译出来的程序会带有符号表和调试信息,一般来说 release 版本在 build 时可以通过添加
-ldflags="-s -w"
编译参数去除调试信息以减小二进制体积。$ go build -ldflags="-s -w" main.go
- s:忽略符号表和调试信息。
- w:忽略DWARFv3调试信息,使用该选项后将无法使用gdb进行调试。
2.2 使用 upx 压缩
UPX (the Ultimate Packer for eXecutables)是一款先进的可执行程序文件压缩器,压缩过的可执行文件体积可以缩小 50%-70%。通过 UPX 压缩过的程序和程序库完全没有功能损失和压缩之前一样可正常地运行,对于支持的大多数格式没有运行时间或内存的不利后果。UPX 支持许多不同的可执行文件格式 包含 Windows 95/98/ME/NT/2000/XP/CE 程序和动态链接库、DOS 程序、 Linux 可执行文件和核心。
另外也可以直接去 github release 页面下载各个平台的二进制程序。
使用:
upx 有很多参数,最重要的则是压缩率,
1-9
,1
代表最低压缩率,9
代表最高压缩率。如果只使用 upx 压缩,可执行文件的体积可以缩小 50%-70%。
样例:
$ upx -9 server
File size Ratio Format Name
-------------------- ------ ----------- -----------
10253684 -> 5210128 50.81% macho/amd64 server
$ ls -lh server
-rwxr-xr-x 1 dj staff 5.0M Dec 8 00:45 server
也可以使用
—-brute
参数尝试所有的压缩方法,以达到最大的压缩比率,但是这样也会消耗更多时间,在 GoReleaser + Github Action 场景中使用可能会超时:$ upx --brute server
3. GoReleaser 配置
使用以上两种压缩方式的 GoReleaser 配置如下,样例:
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
# 使用 ldflags="-s -w" 去掉符号表和调试信息,以减少发布包的大小
ldflags:
- -s -w
# upx 在部分 Mac 系统中会出现 killed 的报错,二进制无法正常工作,请谨慎使用
# hooks:
# post:
# - upx -9 "{{ .Path }}"
# upx 在 windows amd64 上会报错,暂时不用
# ignore:
# - goos: windows
# goarch: arm64
main: ./cmd/mdfmt
注意:
- upx 的配置为了防止在 Github Action 中超时,不使用更高压缩比的
--brute
参数,而是直接使用-9
,以获取最好的压缩比和时间的平衡。
- upx 在部分 Mac 系统中会出现 killed 的报错,二进制无法正常工作