35
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Goでリリースビルドするときに最低限付けておきたいオプション

Last updated at Posted at 2022-08-10

みなさん、Goでビルドするときには、どんなオプションを指定していますか?

Goではgo buildだけでも何事もなくビルドできるので、特に何も指定していないという人もいるかと思います。
しかし、オプションを何も指定せずにビルドした実行ファイルには、デバッグ情報などのリリース時には不要な様々な情報が含まれています。

本稿ではリリースビルドを作成するときに最低限付けておきたいオプションについて、簡単に紹介したいと思います。

※ビルドオプションを網羅的に紹介する記事ではありません。

リリースビルド時に最低限付けたいオプション

Goでリリースビルドを作成する時に最低限付けておきたいオプションは次の2つです。

  • -ldflags="-s -w"
    • デバッグ情報(シンボルテーブル等)を含めないオプション
    • ファイルサイズが小さくなります
  • -trimpath
    • ビルド環境のローカルパス情報を取り除くオプション
    • (ユーザー名などが含まれた)ローカルPC上のパス情報の漏洩を防げます

実際にはこのような感じで使います。

go build -ldflags="-s -w" -trimpath

巷の記事やOSSプロジェクトを見ても、だいたいこのような指定をしているものが多い印象です(-trimpathは無いことも多いですが1)。

以下の項でこの2つのオプションについて簡単に解説します。

-ldflags="-s -w"オプション

-ldflagsは、ビルド時に内部で呼ばれるgo tool linkの引数を指定するオプションとなっていて、今回の指定ではgo tool link -s -wのような感じで実行されることになります。

go tool linkに渡せるオプションについてはlinkコマンドのドキュメントgo tool link --helpで確認できます。

-s-wについてヘルプを確認すると、次のようなことが書かれています。

-s
	Omit the symbol table and debug information.
-w
	Omit the DWARF symbol table.

いずれもシンボルテーブルやデバッグに関する情報を取り除くオプションです。
これらのオプションを指定することで、実行ファイルからデバッグ用の情報が取り除かれ、ファイルサイズがそこそこ小さくなります。

ちなみにシンボルテーブルというのは、関数名や変数名、ソースコード上の位置などの情報を格納したテーブルです。
ただ、Goのスタックトレースに出てくる情報はまた別に持っているようで、これらを指定してもスタックトレースではファイル名や位置が出力されます。

ファイルサイズについて

簡単なhello-worldプログラムで比較してみると、だいたいこのぐらいの違いが出てきます(Go 1.18 on macOSでの一例です)。

オプション ファイルサイズ
なし 1854560 (1.8M)
-ldflags="-s -w" 1346656 (1.3M)
-ldflags="-s -w" -trimpath 1342560 (1.3M)

-trimpathオプション

-trimpathgo buildに対するオプションです。Go 1.13で追加されました。

go buildに渡せるオプションについてはbuildコマンドのドキュメントgo help buildで確認できます。

-trimpathについてヘルプを確認すると、次のようなことが書かれています。

-trimpath
	remove all file system paths from the resulting executable.
	Instead of absolute file system paths, the recorded file names
	will begin either a module path@version (when using modules),
	or a plain import path (when using the standard library, or GOPATH).

通常はビルド環境の絶対パスが実行ファイルに埋め込まれるのですが、これをモジュールやGOPATHからの相対パスとして記録するようになります。

埋め込まれるパス情報について

例えば次のようなディレクトリで開発をしているとします。

/Users/ynakamura/mycompany/myproject

ここで-trimpath付けずにビルドした場合、プログラムがスタックトレースを出力すると、このような感じになります。2

$ ./myproject
panic: error!!

goroutine 1 [running]:
main.main()
	/Users/ynakamura/mycompany/myproject/main.go:4 +0x27

ユーザー名や会社名等の含まれた、開発環境のフルパスが見えてしまっていますね。

一方で、-trimpathを付けてビルドするとこうなります。

$ ./myproject
panic: error!!

goroutine 1 [running]:
main.main()
	myproject/main.go:4 +0x27

プロジェクトディレクトリからの相対パスだけが記録されるようになりました。

おわりに

これら2つのオプションを指定すると、ファイルサイズは小さくなるし、余計な情報が残らないので、リリース時にはぜひとも付けておきたいですね。

シングルバイナリという特性上、ちょっと大きめなGoのバイナリが小さくなるのは嬉しいかと思います。
特にコンテナ環境が多くなりつつある昨今では、コンテナイメージを少しでも小さくするために色々工夫をすることも多いので、そういった面でも効果が期待できます。

パス情報についても、漏れたからといって直ちに情報漏えい等の問題に繋がるわけではありませんが、ビルド環境のパス情報が見えてしまうのはあまり気持ちの良いものではないですし、サーバーのログに残ったりもするので、できれば消しておきたいですね。

  1. -trimpathはGo 1.13(2019年9月リリース)で追加されたオプションです。

  2. stringsコマンドでもファイルに埋め込まれた文字列が確認できます。

35
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?