概要
Go Toolchainはモジュールで使うバージョン管理をgoディレクティブだけの頃よりも正確に制御できます。
しかしビルドバージョンは以下の要素の組み合わせから決定されるため、ちゃんと理解していないと期待しない挙動になることがあります。
- GOTOOLCHAIN環境変数
- ローカルバージョン
- go.modのgoディレクティブ
- go.modのtoolchainディレクティブ
今回は簡単に検証できる環境を紹介して、どうなるのか確認してみます。
環境
- Go v1.21以上
前提知識
goディレクティブとは
go.mod
におけるこれです。
module example.com/myapp go 1.21 // これ
役割
- モジュールで使用するGoの最小バージョンを指定
toolchainディレクティブとは
go.mod
におけるこれです。
module example.com/myapp go 1.21 toolchain go1.21.2 // これ
役割
- モジュールがビルドまたは実行される際に使用されるツールチェインのバージョンを制御
- モジュールが期待するバージョンを明示的に指定
検証環境
こちらに用意した環境のファイルを用意します。
. ├── go.mod └── main.go
main.goの中身はこうです。ビルドされたバージョンを表示するようにします。
package main import ( "fmt" "runtime/debug" ) func main() { info, ok := debug.ReadBuildInfo() if ok && info != nil { fmt.Println("Go Version:", info.GoVersion) } else { fmt.Println("Unable to determine Go version") } }
使い方
基本的な例
例えば次のような設定の場合は
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | 未設定(=local) |
ローカルバージョン | v1.21.3 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.22.1 |
このように実行します。
$ docker run --rm -v "$(pwd)":/app -w /app golang:1.21.3 go run main.go Go Version: go1.21.3
結果はローカルバージョンが優先されてv1.21.3が使われました。
ローカルバージョンを変更する
Docker imageのバージョンを指定します。
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | 未設定(=local) |
ローカルバージョン | v1.22.9 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.21.1 |
$ docker run --rm -v "$(pwd)":/app -w /app golang:1.22.9 go run main.go Go Version: go1.22.9
結果はローカルバージョンが優先されてv1.22.9になります。
GOTOOLCHAIN環境変数にautoを指定する
GOTOOLCHAIN環境変数は未設定の場合localになっています。
$ docker run --rm -v "$(pwd)":/app -w /app golang:1.21 go env GOTOOLCHAIN local
なので今回はautoに指定します。
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | auto |
ローカルバージョン | v1.21.13 |
goディレクティブ | 1.22 |
toolchainディレクティブ | go1.22.1 |
環境変数を渡します。
$ docker run --rm -v "$(pwd)":/app -w /app -e GOTOOLCHAIN=auto golang:1.21 go run main.go go: downloading go1.22.1 (linux/arm64) Go Version: go1.22.1
結果はtoolchainディレクティブが優先されてv1.22.1になります。
GOTOOLCHAIN環境変数にgo1.21.3を指定する
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | go1.21.3 |
ローカルバージョン | v1.22.9 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.21.5 |
環境変数を渡します。
$ docker run --rm -v "$(pwd)":/app -w /app -e GOTOOLCHAIN=go1.21.3 golang:1.22.9 go run main.go go: downloading go1.21.3 (linux/arm64) Go Version: go1.21.3
結果はGOTOOLCHAINが優先されてv1.21.3になります。
toolchainディレクティブをなしにする
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | 未設定(=local) |
ローカルバージョン | v1.21.3 |
goディレクティブ | 1.21 |
toolchainディレクティブ | - |
go.modをいじります。
module github.com/jun06t/go-sample/toolchain go 1.21 //toolchain go1.22.1
$ docker run --rm -v "$(pwd)":/app -w /app golang:1.21.3 go run main.go Go Version: go1.21.3
結果はローカルバージョンが優先されてv1.21.3になります。
結果まとめ
今回の結果(+いくつか追加)は以下になりました。
GOTOOLCHAIN | ローカル | goディレクティブ | toolchainディレクティブ | 結果 |
---|---|---|---|---|
未設定(=local) | 1.21.3 | 1.21 | 1.22.1 | 1.21.3 |
未設定(=local) | 1.22.9 | 1.21 | 1.22.1 | 1.22.9 |
未設定(=local) | 1.22.9 | 1.23 | 1.23.3 | requiresエラー |
auto | 1.21.3 | 1.21.1 | 1.22.1 | 1.22.1 |
go1.21.3 | 1.22.3 | 1.21.1 | 1.21.5 | 1.21.3 |
go1.21.3+auto | 1.22.3 | 1.21.1 | 1.21.5 | 1.21.5 |
未設定(=local) | 1.21.3 | 1.21 | - | 1.21.3 |
path | 1.22.3 | 1.21 | 1.21.5 | 1.22.3 |
path | 1.22.3 | 1.21 | 1.23.3 | cannot findエラー |
こんな感じで簡単に検証ができるので、挙動を確認してみたい方は一度このやり方をやってみてください。