はじめに
フューチャー Advent Calendar 2021の7日目です。
本記事では go build main.go
と go build {パッケージ名}
としてビルドしたときの微妙な違いについて説明します。Goのバージョンは go1.18beta1
で確認しています。
Go 1.18から runtime/debug
パッケージの ReadBuildInfo()
を使って、ビルドしたときのVCSのハッシュを取得できるようになりますが、このビルドしたときの微妙な違いが影響するようになります。1
https://tip.golang.org/doc/go1.18#go-command
go build
の引数による違い
go build
でGoのソースをビルドして、実行バイナリが生成されることはよく知られています。
Usageにあるように
go build [-o output] [build flags] [packages]
パッケージ名 (packages
) を指定してビルドしますが、Goの1つあるいは複数のソースファイルを go build
の引数に渡すこともできます。go build a.go b.go c.go
といったものです。
簡単のために以下のようなディレクトリ、ファイル構成を考えてみます。
.
├── go.mod
└── main.go
module sample
go 1.18
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, 世界")
}
go build ${パッケージ名}
としてビルドしたとき
go build ${パッケージ名}
としてビルドします。本例ではパッケージ名は sample
です。
go version -m sample
で確認すると以下のようになります。path
の値が sample
のパッケージ名になっており、また mod
の値として sample
のパッケージ名が含まれていることが分かります。VCS(ここではGit)のハッシュが含まれていることも分かります。便利ですね。
$ go build sample
$ go version -m sample
sample: go1.18beta1
path sample
mod sample (devel)
build -compiler=gc
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
build vcs=git
build vcs.revision=sample0123456789012345678901234567sample
build vcs.time=2021-12-27T04:24:55Z
build vcs.modified=true
go build main.go
としてビルドしたとき
go build main.go
としてGoのソースファイルを指定してビルドするとコマンドライン引数(command-line-arguments
)としてビルドされます。
go version -m main
で確認すると以下のようになります。path
が command-line-arguments
となっていることが分かります。mod
の値はありません。VCSのハッシュも含まれていません。
$ go build main.go
$ go version -m main
main: go1.18beta1
path command-line-arguments
build -compiler=gc
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1
より詳細を知りたい方へ
Goの標準ライブラリも多くはGoで書かれています。上記の go build
コマンドへの引数による違いは cmd/go/internal/work/build.go
や cmd/go/internal/load/pkg.go
のソースを読んでみると参考になります。cmd/go/internal/load/pkg.go
の中で .go
のファイルが引数として渡されたときは引数がコマンドライン引数として渡されたものとしてフラグ(pkg.Internal.CmdlineFiles
)がセットされます。
func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Package {
// ...
bp, err := ctxt.ImportDir(dir, 0)
pkg := new(Package)
pkg.Internal.Local = true
pkg.Internal.CmdlineFiles = true
pkg.load(ctx, opts, "command-line-arguments", &stk, nil, bp, err)
if !cfg.ModulesEnabled {
pkg.Internal.LocalPrefix = dirToImportPath(dir)
}
pkg.ImportPath = "command-line-arguments"
pkg.Target = ""
pkg.Match = gofiles
// ...
}
まとめ
-
go build
の引数にファイル名を渡すか、パッケージ名を渡すかで、ビルドの方法が異なります。 - ファイル名を渡してビルドした場合は、VCSのハッシュがビルドに含まれません。
- 本挙動は2021/12/30現在Go 1.18のドラフトリリースノートからは確認できませんでした。もしかしたら今後追記されるかも知れません。
- ビルドするときはパッケージ名を指定してビルドしましょう。
-
go version -m
でも確認できます。https://pkg.go.dev/cmd/go#hdr-Print_Go_version ↩