いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-111 (ビルド時にデバッグ情報とかを消してサイズを小さくする, ldflags, trimpath, upx)

概要

go buildldflags オプションを指定するとシンボルやデバッグ情報を削ることができます。

それで、どれくらいサイズが減るのかをメモメモ。

もともと、以下の素晴らしい記事があって、自分でも試してみたいとおもって、今回の記事となりました。

qiita.com

サンプル

この記事で作ったサンプルを github 上にアップしました。よければご参照ください。

github.com

ビルド対象とするソース

以下のような 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

リンカのオプションは以下に説明があります。

golang.org

-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 buildtrimpath というオプションが追加されました。

これを指定すると、panic とかしたときのスタックトレースのパス表示に、ビルド時の実パスがでなくなります。

trimpath オプションについての説明は以下にあります。

golang.org

パス情報を削ってくれるってことなので、これも減るんじゃないかと思って試してみます。

$ 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 がわかりやすいです。

ja.wikipedia.org

upx.github.io

ビルドした後で、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

参考情報

おすすめ書籍

自分が読んだGo関連の本で、いい本って感じたものです。

Go言語による並行処理

Go言語による並行処理

Amazon


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com