Go で作成した CLI ツールにバージョンを埋め込む方法
はじめに
CLI ツールを使う上で切っても切り離せない version
コマンド。
> go version
go version go1.25.0 darwin/arm64
自分がインストールしたツールがどのバージョンなのかを確認する上で非常に重要な機能です。
今回はそんな CLI ツールに欠かせない機能を Go で作成した場合にどうやってバージョン情報を埋め込むのかを調べてみました。
全部で4パターン発見したので、実際に利用されているプロジェクトの例を使ってご紹介します。
他にも方法を知っている方がいましたらぜひ共有してください!
定数/const パターン
最もシンプルな管理方法で定数/const として直接コードでバージョンを管理する方法です。
実装は以下のような形式になります。
※ 参考実例
最もシンプルではありますが、バージョン情報を自動で更新したい場合などに正規表現や静的解析を用いて対象のコードを書き換える必要があります。
go:embed パターン
Go 1.16 で登場した go:embed
機能を利用してファイルでバージョンを管理する方法です。
実装は以下のような形式になります。
※ 参考実例
定数/const パターンと異なり、ファイルで管理するのでコードの書き換えが定数/const パターンより楽に行えるかと思います。
go build -ldflags -X パターン
ビルド時にバージョン情報を渡し
GoReleaser というツールのドキュメントでも紹介されています。
-ldflags
を渡すことでビルド時に内部で呼ばれる go tool link
にオプションを渡すことができます。
成果物のサイズを小さくするために -ldflags="-s -w"
を利用することがあると思います。
-X
オプションを渡すことで特定のパッケージ内の変数に値を設定することが可能になります。
-X importpath.name=value
Set the value of the string variable in importpath named name to value.
This is only effective if the variable is declared in the source code either uninitialized
or initialized to a constant string expression. -X will not work if the initializer makes
a function call or refers to other variables.
Note that before Go 1.5 this option took two separate arguments.
実装は以下のような形式になります。
※ 参考実例
これまで紹介してきたパターンと異なりコードの外からバージョン情報を管理することができるのでバージョン更新のためにコードを変更する必要がなくなります。
更新が楽になった一方で go install
コマンドでインストールした際にはバージョン情報を埋め込むことができないという欠点があります。
buildinfo パターン
Go 1.18 で登場した buildinfo
というパッケージを利用して管理する方法です。
Git の commit id や commit した時刻等のバージョン管理システム(VCS) 情報と、build したアーキテクチャやOS等のビルド情報が取得できます。
つまり、GitHub などでリリースタグを付与しておけば成果物にバージョン情報が含まれることになります。
実装は以下のような形式になります。
※ 参考実例
この方法であれば go install
コマンドを利用してインストールしたとしてもバージョン情報が埋め込まれます。
おわりに
4つのパターンについてご紹介してみました。
これから Go で CLI ツールを作るという方は buildinfo を検討してよいのではないかと思います。
Discussion