Go 1.18 で新しく追加される debug/buildinfo
パッケージについて調べました。
※ 特に記載がない限り 2022 年 2 月 20 日時点 (Go 1.18 rc.1) の情報になります。
概要
従来からビルドに使用された Go のバージョンや依存パッケージの情報はバイナリに含まれており go version -m
で出力できましたが内部パッケージとして実装されているため外部からは利用できませんでした。 1 2
これらの機能を外部から利用できるようにしたのが debug/buildinfo
です。
また、 Go 1.18 ではビルドしたソースコードのバージョン管理情報やビルドオプションもバイナリに追加されるようになりました。
これによって従来は ldflag などで埋め込んでいた git の commit ハッシュなどを runtime から取得できるようになります。
取得できる情報
Go 1.18 では runtime/debug.ReadBuildInfo()
で取得できる debug.BuildInfo
の情報が増えました。
また、 debug/buildinfo
パッケージを使うことで自分自身だけではなく、バイナリファイルまたは io.Reader
から debug.BuildInfo
を取得できるようになりました。
項目名 | 型 | 内容 |
---|---|---|
GoVersion |
string |
ビルドに使用された Go のバージョン文字列 |
Path |
string |
main パッケージパス (既存項目) |
Main |
Module |
main パッケージが含まれるモジュールの情報 (既存項目) |
Deps |
[]*Module |
依存パッケージのモジュール情報 (既存項目) |
Settings |
[]BuildSetting |
ビルドに関する情報 (Key - Value 形式) |
Go 1.18 で追加されたのは GoVersion
と Settings
で他の項目に変更はありません。
手元の環境だと Settings
には次の情報が出力されました。
Key | Value | 内容 |
---|---|---|
-compiler |
gc |
ビルドに使用されたコンパイラ (gc とか gccgo ) |
CGO_ENABLED |
1 |
ビルドに使用される環境変数 |
CGO_CFLAGS |
ビルドに使用される環境変数 | |
CGO_CPPFLAGS |
ビルドに使用される環境変数 | |
CGO_CXXFLAGS |
ビルドに使用される環境変数 | |
CGO_LDFLAGS |
ビルドに使用される環境変数 | |
GOARCH |
amd64 |
ビルドターゲットの CPU アーキテクチャ |
GOOS |
windows |
ビルドターゲットの OS 名 |
GOAMD64 |
v1 |
ビルドターゲット amd64 のマイクロアーキテクチャレベル |
vcs |
git |
バージョン管理システムの名前 (git , hg , bzr , fossil をサポート) |
vcs.revision |
(略) | ソースコードのリビジョンを示す情報 (git の場合は commit ハッシュ) |
vcs.time |
(略) | ソースコードのリビジョン更新時刻 (git の場合は commit 時刻) |
vcs.modified |
true |
commit されていない変更があるかどうか |
GOAMD64
は Go 1.18 で追加される環境変数で amd64
のマイクロアーキテクチャレベルを指定します。 3
デフォルトは v1
で v2
, v3
, v4
と世代が上がると利用できる命令が増えてビルドされるバイナリが最適化されます。
git tag のような情報はバージョンがあいまいになり予測できない動作を引き起こすという理由で含まれていません。 4
個人的に入れてほしい情報ですが commit ハッシュと違って tag は付け替えもできるし複数設定もできるので確かにその通りではあります。
また、バージョン管理システムの情報を含めないオプションを用意するのことでしたが見つけられませんでした。 5
また、ビルド時に -buildvcs=false
を指定することでバージョン管理システムの情報をバイナリに含めないようにできます。
Go 1.18 beta.1 までは -buildinfo=false
を指定することでビルドオプションもバイナリに含めないようにできましたがこのオプションは Go 1.18 beta.2 で廃止されました。 6
ちなみに Main.Version
には (devel)
という文字列が設定されます。
従来からの動作ですが少し残念な感じです。
go version コマンドで出力する
従来の go version -m
は引き続き利用できます。
Go 1.18 でビルドしたバイナリだと表示される情報が増えますが、 Go 1.18 でビルドしたバイナリは Go 1.17 で表示できないようです。
Go 1.17 で go version -m
を使った場合の出力例
$ go version -m testdata/hello.go117.exe
testdata/hello.go117.exe: go1.17.5
path github.com/sg0hsmt/try-goapp/hello
mod github.com/sg0hsmt/try-goapp (devel)
dep github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
dep github.com/maxence-charriere/go-app/v9 v9.2.1 h1:wP+A7zMDc1DIxXvhZQvWVq+vzlb8Hmo75AEVMChoVRg=
$ go version -m testdata/hello.go118.exe
testdata/hello.go118.exe: go version not found
Go 1.18 rc.1 で go version -m
を使った場合の出力例
$ go1.18rc1 version -m testdata/hello.go117.exe
testdata/hello.go117.exe: go1.17.5
path github.com/sg0hsmt/try-goapp/hello
mod github.com/sg0hsmt/try-goapp (devel)
dep github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
dep github.com/maxence-charriere/go-app/v9 v9.2.1 h1:wP+A7zMDc1DIxXvhZQvWVq+vzlb8Hmo75AEVMChoVRg=
$ go1.18rc1 version -m testdata/hello.go118.exe
testdata/hello.go118.exe: go1.18beta1
path github.com/sg0hsmt/try-goapp/hello
mod github.com/sg0hsmt/try-goapp (devel)
dep github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
dep github.com/maxence-charriere/go-app/v9 v9.2.1 h1:wP+A7zMDc1DIxXvhZQvWVq+vzlb8Hmo75AEVMChoVRg=
build -compiler=gc
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=windows
build GOAMD64=v1
build vcs=git
build vcs.revision=619f4a18485903816d91d53a6d1618d5024d47d1
build vcs.time=2021-12-19T07:51:57Z
build vcs.modified=true
Go 1.18 でもビルド時に -buildvcs=false
オプションを指定することでバージョン管理システムの情報が含まれないように制限できます。
-buildvcs=false
と -buildinfo=false
を両方指定するとバイナリに含まれる情報は Go 1.17 と同等になります。
$ go1.18rc1 build -buildvcs=false -o hello.go118.exe .
$ go1.18rc1 version -m hello.go118.exe
hello.go118.exe: go1.18rc1
path github.com/sg0hsmt/try-goapp/hello
mod github.com/sg0hsmt/try-goapp (devel)
dep github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
dep github.com/maxence-charriere/go-app/v9 v9.2.1 h1:wP+A7zMDc1DIxXvhZQvWVq+vzlb8Hmo75AEVMChoVRg=
build -compiler=gc
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=windows
build GOAMD64=v1
なお Go 1.18 rc.1 時点では go version
の対象が実行ファイルに制限されており Windows で Linux 向けバイナリを表示させようとすると失敗します。 7
$ go1.18rc1 version -m testdata/hello.go118.linux
testdata/hello.go118.linux: not executable file
debug/buildinfo パッケージを使う
debug/buildinfo.ReadFile()
にファイルパスを渡すと *debug.BuildInfo
を返してくれるので利用は簡単です。
大雑把に次のようなコードで出力できます。
(Go 1.18 rc.1 で String()
が実装され MarshalText()
が廃止されました 8)
func main() {
var path string
flags := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
flags.StringVar(&path, "path", "", "path of target binary")
flags.Parse(os.Args[1:])
info, err := buildinfo.ReadFile(path)
if err != nil {
log.Fatalln("can not read build info from file:", err)
}
fmt.Println(info)
}
$ go1.18rc1 run main.go -path testdata/hello.go117.exe
go go1.17.5
path github.com/sg0hsmt/try-goapp/hello
mod github.com/sg0hsmt/try-goapp (devel)
dep github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
dep github.com/maxence-charriere/go-app/v9 v9.2.1 h1:wP+A7zMDc1DIxXvhZQvWVq+vzlb8Hmo75AEVMChoVRg=
$ go1.18rc1 run main.go -path testdata/hello.go118.exe
go go1.18beta1
path github.com/sg0hsmt/try-goapp/hello
mod github.com/sg0hsmt/try-goapp (devel)
dep github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
dep github.com/maxence-charriere/go-app/v9 v9.2.1 h1:wP+A7zMDc1DIxXvhZQvWVq+vzlb8Hmo75AEVMChoVRg=
build -compiler=gc
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=windows
build GOAMD64=v1
build vcs=git
build vcs.revision=619f4a18485903816d91d53a6d1618d5024d47d1
build vcs.time=2021-12-19T07:51:57Z
build vcs.modified=true
自分自身の情報を取得したい場合は従来通り debug.ReadBuildInfo()
を呼べば *debug.BuildInfo
を取得できます。
また debug/buildinfo
パッケージを使用した場合は Windows でも Linux 向けバイナリの表示が可能です。
(さすがに wasm はだめでした)
$ go1.18rc1 run main.go -path testdata/hello.go118.linux
go go1.18beta1
path github.com/sg0hsmt/try-goapp/hello
mod github.com/sg0hsmt/try-goapp (devel)
dep github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
dep github.com/maxence-charriere/go-app/v9 v9.2.1 h1:wP+A7zMDc1DIxXvhZQvWVq+vzlb8Hmo75AEVMChoVRg=
build -compiler=gc
build CGO_ENABLED=0
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
build vcs=git
build vcs.revision=619f4a18485903816d91d53a6d1618d5024d47d1
build vcs.time=2021-12-19T07:51:57Z
build vcs.modified=true
ユースケース
主なユースケースとして次の使い方が想定されているようです。
Go で実装されたアプリケーションを運用していくうえで重要な機能になりそうです。
コンテナ内のバイナリに対して脆弱性なパッケージが組み込まれていないかチェックする。
SBOM (ソフトウェア部品表) を作成する。