概要
前回は実際に動かしてみて挙動を確認してみました。今回はそのロジックを理解します。
GoのToolchainはv1.21以降で導入された機能で、次のような課題を解決するために生まれました。
- go.modに記載のバージョンは直感的じゃない
- 実際にビルドに使われるのはローカルにインストールされているGo
- ビルドでコケたらgo.modに記載のバージョンで
module requires Go 1.xx
と言ってくるが、実際に必要な最低バージョンの保証ではない- もしかしたらもう少し低いバージョンでもBuildできる可能性もある
- Go 1.19.4でバグが入ったが、Go 1.19.3, Go 1.19.5 であればBuildできる状態。けれどそれをgo.modで表現できない
またGoでは後方互換性が保証されてはいるものの、複数のプロジェクトにまたがっているとプロジェクトによって使うGoバージョンが決まっていたりするため、何だかんだ複数のバージョン管理ができると良かったりします。
環境
- Go v1.21以上
- macOS v15.1.1
Go Toolchain
Go Toolchainを使うとバージョンを指定してビルドが可能です。
$ GOTOOLCHAIN=go1.21.2 go version go: downloading go1.21.2 (darwin/arm64) go version go1.21.2 darwin/arm64
ただgo.mod
やらGOTOOLCHAIN環境変数
やらが関わってくると期待しない結果になることもあるので、今回はそれを整理します。
GOTOOLCHAIN環境変数
Go Toolchainsを使う上でまず重要なのがGOTOOLCHAIN環境変数です。
これの設定値によって挙動が大きく変わります。
設定値
値 | どうなるか | PATHに無ければダウンロードするか | 例 |
---|---|---|---|
local |
ローカルインストールされたバージョンを使用する | しない。 go directiveのバージョン以下だとrequireエラー |
- |
auto |
local+auto の省略。ローカル、go directive、toolchain directiveの設定を参照して最も新しいGoバージョンを使う |
する | - |
<name> |
指定したバージョンを使用する。 | する | go1.21.0 |
<name>+auto |
指定したバージョン、go directive、toolchain directiveの設定を参照して最も新しいGoバージョンを使う。 ローカルバージョンは考慮しない |
する | go1.21.3+auto |
<name>+path |
指定したバージョン、go directive、toolchain directiveの設定を参照する。 ローカルバージョンは考慮しない。 |
しない。 PATHになければcannot findエラー |
go1.21.3+path |
path |
local+path の省略。ローカル、go directive、toolchain directiveの設定を参照して最も新しいGoバージョンを使う |
しない。 PATHになければcannot findエラー |
- |
設定ロジック
GOTOOLCHAINの設定ロジックは次のようなフローになっています。
※ドキュメント上ではデフォルト値はauto
と書いてありますが、自分のmacOSやdocker go image等で使うとlocal
でした。
ユーザデフォルト環境
ユーザ環境におけるGoに関わる環境変数のデフォルト設定です。
$ go env -w GOTOOLCHAIN=xxx
をしたときの保存されます。ファイルの保存先はOSによって異なります。コマンドで確認することができ、macOSの場合は以下です。
$ go env GOENV /Users/jun06t/Library/Application Support/go/env
登録
登録方法はこちら
$ go env -w GOTOOLCHAIN=auto
確認
確認するときはこちら
$ go env GOTOOLCHAIN
削除
削除するときは環境変数だけ入力します。
$ go env -u GOTOOLCHAIN
理解度チェック
これらを理解していると、前回の挙動も実際に試さずに求められます。
Q1 local
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | 未設定 |
ローカルバージョン | v1.21.3 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.22.1 |
解き方
- GOTOOLCHAIN環境変数が
未設定
だと前述の設定ロジックからlocal
になっている- ※ただしこれはgo.envファイルやユーザデフォルト環境に依存
local
の場合ローカルバージョンを優先するのでv1.21.3
Q2 auto
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | auto |
ローカルバージョン | v1.21.3 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.22.1 |
解き方
- GOTOOLCHAIN環境変数が
auto
なのでローカル、go directive、toolchain directiveの設定を参照して最も新しいGoバージョンを使う - その中で一番新しいのはtoolchainディレクティブで、
1.22.1
Q3 <name>+auto
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | go1.21.3+auto |
ローカルバージョン | v1.22.3 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.21.5 |
解き方
- GOTOOLCHAIN環境変数が
<name>+auto
なので、go directive、toolchain directiveの設定を参照して最も新しいGoバージョンを使う- ※ローカルバージョンは使わない
- その中で一番新しいのはtoolchainディレクティブで、
1.21.5
Q4 path
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | path |
ローカルバージョン | v1.22.3 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.21.5 |
解き方
- GOTOOLCHAIN環境変数が
path
なのでローカル、go directive、toolchain directiveの設定を参照して最も新しいGoバージョンを使う- ※ただしPATHに無ければダウンロードしない
- 今回はローカルが一番新しいので、
1.22.3
Q5 path
最後は難しいです。
要素 | 設定値 |
---|---|
GOTOOLCHAIN環境変数 | path |
ローカルバージョン | v1.22.3 |
goディレクティブ | 1.21 |
toolchainディレクティブ | go1.23.3 |
解き方
- GOTOOLCHAIN環境変数が
path
なのでローカル、go directive、toolchain directiveの設定を参照して最も新しいGoバージョンを使う- ※ただしPATHに無ければダウンロードしない
- 今回はtoolchain directiveが一番新しい、しかしPATHにはないので
cannot findエラー
になる
まとめ
GoのToolchainはプロジェクトによって複数のバージョンを区別して使える非常に便利な仕組みですが、そのロジックをきちんと理解していないと(特にGOTOOLCHAINの決定ロジックと挙動)、実際どのバージョンになるかが期待通りにならないことがあります。
前回と今回の内容を理解すれば問題無く利用できるようになると思います。