- 概要
- サンプル
- ビルド対象とするソース
- 普通にビルド
- ldflags オプションを付けてビルド
- trimpath オプションを付けてビルド
- ldflags と trimpath を両方指定してビルド
- ビルドしたものに upx で圧縮かける
- 全部の実行結果まとめ
- 参考情報
- おすすめ書籍
概要
go build
で ldflags
オプションを指定するとシンボルやデバッグ情報を削ることができます。
それで、どれくらいサイズが減るのかをメモメモ。
もともと、以下の素晴らしい記事があって、自分でも試してみたいとおもって、今回の記事となりました。
サンプル
この記事で作ったサンプルを github 上にアップしました。よければご参照ください。
ビルド対象とするソース
以下のような hello world に毛が生えたものでやります。
package main import ( "fmt" "os" "strconv" "github.com/devlights/gomy/output" ) func main() { os.Exit(run()) } func run() int { fmt.Printf("hello %s[%s]\n", "Go", strconv.Itoa(999)) output.Stdoutl("[message]", "hello Go") return 0 }
普通にビルド
go build
で普通にビルドすると
$ go build -o bin/build-normal main.go $ ls -lh -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:02 build-normal
大体 2MB ってところですね。
ldflags オプションを付けてビルド
go build
時に最後にリンク処理が走るのですが、その時にリンカにオプションを渡すことができます。
$ go build -ldflags '-s -w' -o bin/build-with-ldflags main.go
リンカのオプションは以下に説明があります。
-s
と -w
を指定するとシンボルとデバッグ情報を削ってくれるって感じですね。
サイズは
$ $ ls -l -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:09 build-normal -rwxr-xr-x 1 gitpod gitpod 1.4M Oct 21 10:09 build-with-ldflags
お、減りましたね。
trimpath オプションを付けてビルド
Go1.13より go build
に trimpath
というオプションが追加されました。
これを指定すると、panic とかしたときのスタックトレースのパス表示に、ビルド時の実パスがでなくなります。
trimpath
オプションについての説明は以下にあります。
パス情報を削ってくれるってことなので、これも減るんじゃないかと思って試してみます。
$ go build -trimpath -o bin/build-with-trimpath main.go $ ls -lh -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:09 build-normal -rwxr-xr-x 1 gitpod gitpod 1.4M Oct 21 10:09 build-with-ldflags -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:09 build-with-trimpath
変わらないですね。
ldflags と trimpath を両方指定してビルド
$ go build -ldflags '-s -w' -trimpath -o bin/build-with-trimpath-ldflags main.go $ ls -lh -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:09 build-normal -rwxr-xr-x 1 gitpod gitpod 1.4M Oct 21 10:09 build-with-ldflags -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:09 build-with-trimpath -rwxr-xr-x 1 gitpod gitpod 1.4M Oct 21 10:09 build-with-trimpath-ldflags
まあ、そうなりますよね。
ビルドしたものに upx で圧縮かける
最後に upx つかって、圧縮したらどうなるかです。
upx って何ぞやって場合は、wikipedia がわかりやすいです。
ビルドした後で、upx で圧縮かけてみます。
$ go build -ldflags '-s -w' -trimpath -o bin/build-with-trimpath-ldflags main.go $ upx --lzma -o bin/build-with-upx bin/build-with-trimpath-ldflags $ ls -lh -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:09 build-normal -rwxr-xr-x 1 gitpod gitpod 1.4M Oct 21 10:09 build-with-ldflags -rwxr-xr-x 1 gitpod gitpod 2.0M Oct 21 10:09 build-with-trimpath -rwxr-xr-x 1 gitpod gitpod 1.4M Oct 21 10:09 build-with-trimpath-ldflags -rwxr-xr-x 1 gitpod gitpod 443K Oct 21 10:09 build-with-upx
めっちゃ小さくなりました。さすが upx。
実行速度は?
upx は圧縮をかけているので、実行したら最初に解凍処理が走ります。
そこの部分はオーバーヘッドになりますが、一旦解凍できてしまえば後は同じはずです。
一応ためしてみましょう。
$ time -p bin/build-normal hello Go[999] [message] hello Go real 0.00 user 0.00 sys 0.00 $ time -p bin/build-with-trimpath hello Go[999] [message] hello Go real 0.00 user 0.00 sys 0.00 $ time -p bin/build-with-trimpath-ldflags hello Go[999] [message] hello Go real 0.00 user 0.00 sys 0.00 $ time -p bin/build-with-upx hello Go[999] [message] hello Go real 0.05 user 0.05 sys 0.00
ほんの少しだけ、時間かかってますね。まあ、こんなの気になるレベルではないですが。
全部の実行結果まとめ
$ make rm -f -r bin mkdir -p bin ----------------------------------------------------------- go build -o bin/build-normal main.go go build "-ldflags=-s -w" -o bin/build-with-ldflags main.go go build -trimpath -o bin/build-with-trimpath main.go go build "-ldflags=-s -w" -trimpath -o bin/build-with-trimpath-ldflags main.go upx --lzma -o bin/build-with-upx bin/build-with-trimpath-ldflags Ultimate Packer for eXecutables Copyright (C) 1996 - 2018 UPX 3.95 Markus Oberhumer, Laszlo Molnar & John Reiser Aug 26th 2018 File size Ratio Format Name -------------------- ------ ----------- ----------- 1409024 -> 452852 32.14% linux/amd64 build-with-upx Packed 1 file. ----------------------------------------------------------- ls -1 bin/build* | xargs wc -c | head -n -1 2056769 bin/build-normal 1409024 bin/build-with-ldflags 2056769 bin/build-with-trimpath 1409024 bin/build-with-trimpath-ldflags 452852 bin/build-with-upx ----------------------------------------------------------- time -p bin/build-normal hello Go[999] [message] hello Go real 0.00 user 0.00 sys 0.00 ----------------------------------------------------------- time -p bin/build-with-ldflags hello Go[999] [message] hello Go real 0.00 user 0.00 sys 0.00 ----------------------------------------------------------- time -p bin/build-with-trimpath hello Go[999] [message] hello Go real 0.00 user 0.00 sys 0.00 ----------------------------------------------------------- time -p bin/build-with-trimpath-ldflags hello Go[999] [message] hello Go real 0.00 user 0.00 sys 0.00 ----------------------------------------------------------- time -p bin/build-with-upx hello Go[999] [message] hello Go real 0.05 user 0.05 sys 0.00
参考情報
- How to reduce compiled file size?
- [v1.13版] goでスタティックバイナリを生成する方法
- go tool link
- [Linux]wcコマンドの意外な使い方
- Remove the last line from a file in Bash
- デバッグ情報の歩き方
- What does the w flag mean when passed in via the ldflags option to the go command?
おすすめ書籍
自分が読んだGo関連の本で、いい本って感じたものです。
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場