Carpe Diem

備忘録

Go Toolchainの挙動を確認する【理論編】

概要

前回は実際に動かしてみて挙動を確認してみました。今回はそのロジックを理解します。

christina04.hatenablog.com

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の決定ロジックと挙動)、実際どのバージョンになるかが期待通りにならないことがあります。

前回と今回の内容を理解すれば問題無く利用できるようになると思います。

参考