Go ツールチェーン
はじめに
Go 1.21 以降、Go ディストリビューションは go コマンドと、標準ライブラリ、コンパイラ、アセンブラ、その他のツールを含むバンドルされた Go ツールチェーンで構成されます。go コマンドは、バンドルされた Go ツールチェーンだけでなく、ローカルの PATH で見つけるか、必要に応じてダウンロードする他のバージョンも使用できます。
使用される Go ツールチェーンの選択は、GOTOOLCHAIN 環境設定と、メインモジュールの go.mod ファイルまたは現在のワークスペースの go.work ファイル内の go および toolchain 行に依存します。異なるメインモジュールやワークスペース間を移動すると、モジュールの依存関係のバージョンと同様に、使用されるツールチェーンのバージョンも変化する可能性があります。
標準構成では、go コマンドは、そのツールチェーンがメインモジュールまたはワークスペースの go または toolchain 行よりも新しい場合に、独自のバンドルされたツールチェーンを使用します。たとえば、go 1.21.0 と記述されたメインモジュールで Go 1.21.3 にバンドルされた go コマンドを使用する場合、go コマンドは Go 1.21.3 を使用します。go または toolchain 行がバンドルされたツールチェーンよりも新しい場合、go コマンドは代わりに新しいツールチェーンを実行します。たとえば、go 1.21.9 と記述されたメインモジュールで Go 1.21.3 にバンドルされた go コマンドを使用する場合、go コマンドは Go 1.21.9 を見つけて実行します。まず PATH で go1.21.9 という名前のプログラムを探し、それ以外の場合は Go 1.21.9 ツールチェーンのコピーをダウンロードしてキャッシュします。この自動ツールチェーン切り替えは無効にできますが、その場合、より正確な前方互換性のために、go コマンドは、go 行が新しいバージョンの Go を要求するメインモジュールまたはワークスペースでは実行を拒否します。つまり、go 行は、モジュールまたはワークスペースを使用するために必要な最小限の Go バージョンを設定します。
他のモジュールの依存関係であるモジュールは、そのモジュールで直接作業する場合に、優先ツールチェーンよりも低い最小 Go バージョン要件を設定する必要がある場合があります。この場合、go.mod または go.work の toolchain 行は、go コマンドが使用するツールチェーンを決定する際に、go 行よりも優先される推奨ツールチェーンを設定します。
go および toolchain 行は、go.mod の require 行が他のモジュールの依存関係のバージョン要件を指定するのと同様に、モジュールの Go ツールチェーン自体への依存関係のバージョン要件を指定していると考えることができます。go get コマンドは、他のモジュールへの依存関係を管理するのと同様に、Go ツールチェーンの依存関係を管理します。たとえば、go get go@latest は、最新リリースの Go ツールチェーンを要求するようにモジュールを更新します。
GOTOOLCHAIN 環境設定は、特定の Go バージョンを強制し、go および toolchain 行を上書きすることができます。たとえば、Go 1.21rc3 でパッケージをテストするには
GOTOOLCHAIN=go1.21rc3 go test
デフォルトの GOTOOLCHAIN 設定は auto で、これは前述のツールチェーン切り替えを有効にします。代替形式 <name>+auto は、さらに切り替えるかどうかを決定する前に使用するデフォルトのツールチェーンを設定します。たとえば、GOTOOLCHAIN=go1.21.3+auto は、go コマンドに、デフォルトで Go 1.21.3 を使用するという決定を開始させますが、go および toolchain 行によって指示された場合は、より新しいツールチェーンを依然として使用します。デフォルトの GOTOOLCHAIN 設定は go env -w で変更できるため、Go 1.21.0 以降がインストールされている場合は、
go env -w GOTOOLCHAIN=go1.21.3+auto
は、Go 1.21.0 のインストールを Go 1.21.3 に置き換えることと同等です。
このドキュメントの残りの部分では、Go ツールチェーンがどのようにバージョン管理され、選択され、管理されるかをより詳しく説明します。
Go バージョン
Go のリリースバージョンは、'1.N.P' というバージョン構文を使用し、Go 1.N の P 番目のリリースを示します。最初のリリースは 1.N.0 で、'1.21.0' のようになります。1.N.9 のような後のリリースは、しばしばパッチリリースと呼ばれます。
Go 1.N のリリース候補は、1.N.0 の前に発行され、'1.NrcR' というバージョン構文を使用します。Go 1.N の最初のリリース候補のバージョンは 1.Nrc1 で、1.23rc1 のようになります。
'1.N' という構文は「言語バージョン」と呼ばれます。これは、Go 言語と標準ライブラリのそのバージョンを実装する Go リリースの全体的なファミリーを示します。
Go バージョンの言語バージョンは、N の後のすべてを切り捨てた結果です: 1.21、1.21rc2、および 1.21.3 はすべて言語バージョン 1.21 を実装します。
Go 1.21.0 や Go 1.21rc1 のようなリリースされた Go ツールチェーンは、go version および runtime.Version からその特定のバージョン (例: go1.21.0 または go1.21rc1) を報告します。Go 開発リポジトリからビルドされた未リリース (開発中) の Go ツールチェーンは、代わりに言語バージョンのみを報告します (例: go1.21)。
任意の 2 つの Go バージョンは、どちらかがもう一方より小さいか、大きいか、または等しいかを決定するために比較できます。言語バージョンが異なる場合、それが比較を決定します: 1.21.9 < 1.22。言語バージョン内では、最小から最大への順序は、言語バージョン自体、次に R で順序付けされたリリース候補、次に P で順序付けされたリリースです。
たとえば、1.21 < 1.21rc1 < 1.21rc2 < 1.21.0 < 1.21.1 < 1.21.2 です。
Go 1.21 以前は、Go ツールチェーンの最初のリリースは 1.N であり、1.N.0 ではありませんでした。したがって、N < 21 の場合、順序はリリース候補の後に 1.N が来るように調整されます。
たとえば、1.20rc1 < 1.20rc2 < 1.20rc3 < 1.20 < 1.20.1 です。
以前のバージョンの Go には、1.18beta2 のようなバージョンを持つベータリリースがありました。ベータリリースは、バージョンの順序付けでリリース候補の直前に置かれます。
たとえば、1.18beta1 < 1.18beta2 < 1.18rc1 < 1.18 < 1.18.1 です。
Go ツールチェーン名
標準の Go ツールチェーンは goV と名付けられ、V はベータリリース、リリース候補、またはリリースを示す Go バージョンです。たとえば、go1.21rc1 と go1.21.0 はツールチェーン名です。go1.21 と go1.22 はそうではありません (最初のリリースは go1.21.0 と go1.22.0 です) が、go1.20 と go1.19 はそうです。
非標準のツールチェーンは、任意のサフィックスに対して goV-suffix の形式の名前を使用します。
ツールチェーンは、名前に埋め込まれたバージョン V を比較することで比較されます (最初の go を削除し、- で始まるサフィックスを破棄します)。たとえば、go1.21.0 と go1.21.0-custom は、順序付けの目的では等しく比較されます。
モジュールとワークスペースの構成
Go モジュールとワークスペースは、go.mod または go.work ファイルでバージョン関連の構成を指定します。
go 行は、モジュールまたはワークスペースを使用するための最小限必要な Go バージョンを宣言します。互換性の理由から、go.mod ファイルから go 行が省略された場合、モジュールには暗黙的な go 1.16 行があると見なされ、go.work ファイルから go 行が省略された場合、ワークスペースには暗黙的な go 1.18 行があると見なされます。
toolchain 行は、モジュールまたはワークスペースで使用する推奨ツールチェーンを宣言します。以下の「Go ツールチェーンの選択」で説明されているように、デフォルトのツールチェーンのバージョンが推奨ツールチェーンのバージョンよりも古い場合、go コマンドは、そのモジュールまたはワークスペースで操作する際にこの特定のツールチェーンを実行する場合があります。toolchain 行が省略された場合、モジュールまたはワークスペースには暗黙的な toolchain goV 行があると見なされ、ここで V は go 行からの Go バージョンです。
たとえば、toolchain 行がない go 1.21.0 と記述された go.mod は、toolchain go1.21.0 行があるかのように解釈されます。
Go ツールチェーンは、ツールチェーン自身のバージョンよりも大きな最小必要 Go バージョンを宣言するモジュールまたはワークスペースのロードを拒否します。
たとえば、Go 1.21.2 は、go 1.21.3 または go 1.22 行を持つモジュールまたはワークスペースのロードを拒否します。
モジュールの go 行は、require ステートメントにリストされている各モジュールによって宣言された go バージョン以上を宣言する必要があります。ワークスペースの go 行は、use ステートメントにリストされている各モジュールによって宣言された go バージョン以上を宣言する必要があります。
たとえば、モジュール M が go 1.22.0 を宣言する go.mod を持つ依存関係 D を必要とする場合、M の go.mod は go 1.21.3 とは記述できません。
各モジュールの go 行は、そのモジュールのパッケージをコンパイルする際にコンパイラが強制する言語バージョンを設定します。言語バージョンは、ビルド制約を使用することでファイルごとに変更できます。ビルド制約が存在し、少なくとも go1.21 の最小バージョンを意味する場合、そのファイルをコンパイルする際に使用される言語バージョンはその最小バージョンになります。
たとえば、Go 1.21 言語バージョンを使用するコードを含むモジュールは、go 1.21 または go 1.21.3 のような go 行を持つ go.mod ファイルを持つ必要があります。特定のソースファイルが新しい Go ツールチェーンを使用する場合にのみコンパイルされるようにするには、そのソースファイルに //go:build go1.22 を追加すると、Go 1.22 以降のツールチェーンのみがファイルをコンパイルすることを保証し、そのファイル内の言語バージョンを Go 1.22 に変更します。
go および toolchain 行は、go get を使用して最も便利かつ安全に変更できます。以下の go get 専用のセクションを参照してください。
Go 1.21 以前は、Go ツールチェーンは go 行を推奨要件として扱っていました。ビルドが成功すればツールチェーンはすべてが機能したと仮定し、そうでない場合は潜在的なバージョン不一致に関する注意を印刷しました。Go 1.21 は、go 行を強制要件に変更しました。この動作は、以前の言語バージョンにも部分的にバックポートされています。Go 1.19.13 以降の Go 1.19 リリースと Go 1.20.8 以降の Go 1.20 リリースは、バージョン Go 1.22 以降を宣言するワークスペースまたはモジュールのロードを拒否します。
Go 1.21 以前は、ツールチェーンは、モジュールまたはワークスペースがその依存モジュールごとに要求される go バージョン以上の go 行を持つことを要求しませんでした。
GOTOOLCHAIN 設定
go コマンドは、GOTOOLCHAIN 設定に基づいて使用する Go ツールチェーンを選択します。GOTOOLCHAIN 設定を見つけるために、go コマンドは任意の Go 環境設定に関する標準ルールを使用します
-
プロセス環境で
GOTOOLCHAINが空でない値に設定されている場合 (os.Getenvでクエリされた場合)、goコマンドはその値を使用します。 -
そうでない場合、ユーザーの環境デフォルトファイル (
go env -wおよびgo env -uで管理) でGOTOOLCHAINが設定されている場合、goコマンドはその値を使用します。 -
そうでない場合、バンドルされた Go ツールチェーンの環境デフォルトファイル (
$GOROOT/go.env) でGOTOOLCHAINが設定されている場合、goコマンドはその値を使用します。
標準の Go ツールチェーンでは、$GOROOT/go.env ファイルはデフォルトの GOTOOLCHAIN=auto を設定しますが、再パッケージ化された Go ツールチェーンはこの値を変更する場合があります。
$GOROOT/go.env ファイルが見つからないか、デフォルトが設定されていない場合、go コマンドは GOTOOLCHAIN=local と仮定します。
go env GOTOOLCHAIN を実行すると、GOTOOLCHAIN 設定が表示されます。
Go ツールチェーンの選択
起動時に、go コマンドは使用する Go ツールチェーンを選択します。GOTOOLCHAIN 設定を参照します。これは <name>、<name>+auto、または <name>+path の形式を取ります。GOTOOLCHAIN=auto は GOTOOLCHAIN=local+auto の短縮形です。同様に、GOTOOLCHAIN=path は GOTOOLCHAIN=local+path の短縮形です。<name> はデフォルトの Go ツールチェーンを設定します。local はバンドルされた Go ツールチェーン (実行中の go コマンドに付属していたもの) を示し、それ以外の場合、<name> は go1.21.0 のような特定の Go ツールチェーン名でなければなりません。go コマンドはデフォルトの Go ツールチェーンを実行することを優先します。上記のように、Go 1.21 以降、Go ツールチェーンは新しい Go バージョンを必要とするワークスペースやモジュールでの実行を拒否します。代わりに、エラーを報告して終了します。
GOTOOLCHAIN が local に設定されている場合、go コマンドは常にバンドルされた Go ツールチェーンを実行します。
GOTOOLCHAIN が <name> に設定されている場合 (たとえば、GOTOOLCHAIN=go1.21.0)、go コマンドは常にその特定の Go ツールチェーンを実行します。その名前のバイナリがシステム PATH で見つかった場合、go コマンドはそれを使用します。それ以外の場合、go コマンドはダウンロードして検証する Go ツールチェーンを使用します。
GOTOOLCHAIN が <name>+auto または <name>+path (または短縮形 auto または path) に設定されている場合、go コマンドは必要に応じて新しい Go バージョンを選択して実行します。具体的には、現在のワークスペースの go.work ファイル、またはワークスペースがない場合はメインモジュールの go.mod ファイル内の toolchain および go 行を参照します。go.work または go.mod ファイルに toolchain <tname> 行があり、<tname> がデフォルトの Go ツールチェーンよりも新しい場合、go コマンドは代わりに <tname> を実行します。ファイルに toolchain default 行がある場合、go コマンドはデフォルトの Go ツールチェーンを実行し、<name> を超える更新の試みを無効にします。それ以外の場合、ファイルに go <version> 行があり、<version> がデフォルトの Go ツールチェーンよりも新しい場合、go コマンドは代わりに go<version> を実行します。
バンドルされた Go ツールチェーン以外のツールチェーンを実行するために、go コマンドは、指定された名前 (たとえば、go1.21.3) のプログラムをプロセスの実行可能パス (Unix および Plan 9 では $PATH、Windows では %PATH%) で検索し、そのプログラムを実行します。そのようなプログラムが見つからない場合、go コマンドは指定された Go ツールチェーンをダウンロードして実行します。GOTOOLCHAIN 形式 <name>+path を使用すると、ダウンロードのフォールバックが無効になり、go コマンドは実行可能パスの検索後に停止します。
go version を実行すると、選択された Go ツールチェーンのバージョン (選択されたツールチェーンの go version の実装を実行することによって) が出力されます。
GOTOOLCHAIN=local go version を実行すると、バンドルされた Go ツールチェーンのバージョンが出力されます。
Go 1.24 以降、go コマンドを実行するときに GODEBUG 環境変数に toolchaintrace=1 を追加することで、go コマンドのツールチェーン選択プロセスをトレースできます。
Go ツールチェーンの切り替え
ほとんどのコマンドでは、ワークスペースの go.work またはメインモジュールの go.mod は、バージョン順序付けの構成要件により、任意のモジュール依存関係の go 行と同じかそれよりも新しい go 行を持っています。この場合、起動時のツールチェーン選択は、コマンドを完了するのに十分な新しい Go ツールチェーンを実行します。
一部のコマンドは、操作の一部として新しいモジュールバージョンを組み込みます。go get は新しいモジュール依存関係をメインモジュールに追加します。go work use は新しいローカルモジュールをワークスペースに追加します。go work sync は、ワークスペースが作成されてから更新された可能性のあるローカルモジュールとワークスペースを再同期します。go install package@version および go run package@version は、実質的に空のメインモジュールで実行され、package@version を新しい依存関係として追加します。これらのすべてのコマンドは、現在実行されている Go バージョンよりも新しい Go バージョンを必要とする go.mod の go 行を持つモジュールに遭遇する可能性があります。
コマンドが新しい Go バージョンを必要とするモジュールに遭遇し、GOTOOLCHAIN が異なるツールチェーンの実行を許可する場合 (auto または path のいずれかの形式の場合)、go コマンドは現在のコマンドの実行を続行するために適切な新しいツールチェーンを選択して切り替えます。
go コマンドが起動時のツールチェーン選択後にツールチェーンを切り替える場合、その理由を説明するメッセージを出力します。たとえば
go: module example.com/widget@v1.2.3 requires go >= 1.24rc1; switching to go 1.27.9
例に示すように、go コマンドは、検出された要件よりも新しいツールチェーンに切り替える場合があります。一般に、go コマンドはサポートされている Go ツールチェーンに切り替えることを目指します。
ツールチェーンを選択するために、go コマンドはまず利用可能なツールチェーンのリストを取得します。auto 形式の場合、go コマンドは利用可能なツールチェーンのリストをダウンロードします。path 形式の場合、go コマンドは PATH をスキャンして有効なツールチェーンと名付けられた実行可能ファイルを探し、見つけたすべてのツールチェーンのリストを使用します。そのツールチェーンのリストを使用して、go コマンドは最大 3 つの候補を特定します
- 未リリースの Go 言語バージョンの最新リリース候補 (1.N₃rcR₃)、
- 最新リリースされた Go 言語バージョンの最新パッチリリース (1.N₂.P₂)、および
- 以前の Go 言語バージョンの最新パッチリリース (1.N₁.P₁)。
これらは、Go のリリースポリシーに従ってサポートされている Go リリースです。最小バージョン選択と整合性があり、go コマンドはその後、新しい要件を満たす**最小** (最も古い) バージョンの候補を保守的に使用します。
たとえば、example.com/widget@v1.2.3 が Go 1.24rc1 以降を必要とするとします。go コマンドは利用可能なツールチェーンのリストを取得し、2 つの最も新しい Go ツールチェーンの最新パッチリリースが Go 1.28.3 と Go 1.27.9 であり、リリース候補 Go 1.29rc2 も利用可能であることを見つけます。この状況では、go コマンドは Go 1.27.9 を選択します。widget が Go 1.28 以降を必要とした場合、Go 1.27.9 は古すぎるため、go コマンドは Go 1.28.3 を選択します。widget が Go 1.29 以降を必要とした場合、Go 1.27.9 と Go 1.28.3 の両方が古すぎるため、go コマンドは Go 1.29rc2 を選択します。
新しい Go バージョンを必要とする新しいモジュールバージョンを組み込むコマンドは、新しい最小 go バージョン要件を現在のワークスペースの go.work ファイルまたはメインモジュールの go.mod ファイルに書き込み、go 行を更新します。再現性のために、go 行を更新するコマンドは、自身のツールチェーン名を記録するために toolchain 行も更新します。次に go コマンドがそのワークスペースまたはモジュールで実行されるとき、ツールチェーン選択中にその更新された toolchain 行を使用します。
たとえば、go get example.com/widget@v1.2.3 は上記のような切り替え通知を印刷し、Go 1.27.9 に切り替える場合があります。Go 1.27.9 は go get を完了し、toolchain 行を toolchain go1.27.9 に更新します。次にそのモジュールまたはワークスペースで実行される go コマンドは、起動時に go1.27.9 を選択し、切り替えメッセージは印刷されません。
一般に、go コマンドが 2 回実行され、最初のコマンドが切り替えメッセージを印刷した場合、2 番目のコマンドは印刷しません。なぜなら、最初のコマンドは起動時に正しいツールチェーンを選択するために go.work または go.mod も更新したからです。例外は、ワークスペースやメインモジュールで実行されず、toolchain 行を書き込むことができない go install package@version および go run package@version 形式です。これらは、新しいツールチェーンに切り替える必要があるたびに切り替えメッセージを印刷します。
ツールチェーンのダウンロード
GOTOOLCHAIN=auto または GOTOOLCHAIN=<name>+auto を使用する場合、Go コマンドは必要に応じて新しいツールチェーンをダウンロードします。これらのツールチェーンは、モジュールパス golang.org/toolchain とバージョン v0.0.1-goVERSION.GOOS-GOARCH を持つ特別なモジュールとしてパッケージ化されます。ツールチェーンは他のモジュールと同様にダウンロードされます。つまり、ツールチェーンのダウンロードは GOPROXY を設定することでプロキシでき、Go チェックサムデータベースによってチェックサムがチェックされます。使用される特定のツールチェーンは、システムのデフォルトツールチェーンとローカルオペレーティングシステムおよびアーキテクチャ (GOOS および GOARCH) に依存するため、go.sum にツールチェーンモジュールのチェックサムを書き込むことは実用的ではありません。代わりに、GOSUMDB=off の場合、検証不足のためにツールチェーンのダウンロードは失敗します。GOPRIVATE および GONOSUMDB パターンはツールチェーンのダウンロードには適用されません。
go get を使用した Go バージョンモジュール要件の管理
一般に、go コマンドは、go および toolchain 行をメインモジュールのバージョン管理されたツールチェーン依存関係の宣言として扱います。go get コマンドは、バージョン管理されたモジュール依存関係を指定する require 行を管理するのと同様に、これらの行を管理できます。
たとえば、go get go@1.22.1 toolchain@1.24rc1 は、メインモジュールの go.mod ファイルを go 1.22.1 および toolchain go1.24rc1 に変更します。
go コマンドは、go 依存関係が、より大きいか等しい Go バージョンの toolchain 依存関係を必要とすることを理解しています。
例を続けると、その後の go get go@1.25.0 はツールチェーンも go1.25.0 に更新します。ツールチェーンが go 行と正確に一致する場合、省略して暗黙的に指定できるため、この go get は toolchain 行を削除します。
同じ要件はダウングレードの場合にも逆方向に適用されます。go.mod が go 1.22.1 と toolchain go1.24rc1 で開始する場合、go get toolchain@go1.22.9 は toolchain 行のみを更新しますが、go get toolchain@go1.21.3 は go 行も go 1.21.3 にダウングレードします。その結果、toolchain 行なしで go 1.21.3 のみが残ります。
特殊な形式 toolchain@none は、go get toolchain@none または go get go@1.25.0 toolchain@none のように、任意の toolchain 行を削除することを意味します。
go コマンドは、クエリだけでなく、go および toolchain 依存関係のバージョン構文も理解しています。
たとえば、go get example.com/widget@v1.2 が example.com/widget の最新の v1.2 バージョン (おそらく v1.2.3) を使用するのと同様に、go get go@1.22 は Go 1.22 言語バージョンの最新の利用可能なリリース (おそらく 1.22rc3、またはおそらく 1.22.3) を使用します。同じことが go get toolchain@go1.22 にも適用されます。
go get および go mod tidy コマンドは、go 行が、必要な依存モジュールの go 行以上になるように維持します。
たとえば、メインモジュールが go 1.22.1 を持ち、go 1.24rc1 を宣言する go get example.com/widget@v1.2.3 を実行した場合、go get はメインモジュールの go 行を go 1.24rc1 に更新します。
例を続けると、その後の go get go@1.22.1 は example.com/widget を Go 1.22.1 と互換性のあるバージョンにダウングレードするか、example.com/widget の他の依存関係をダウングレードする場合と同様に、要件を完全に削除します。
Go 1.21 以前は、モジュールを新しい Go バージョン (たとえば Go 1.22) に更新する推奨方法は go mod tidy -go=1.22 でした。これにより、Go 1.22 に固有の調整が go 行の更新と同時に go.mod に適用されることが保証されました。その形式はまだ有効ですが、より単純な go get go@1.22 が現在では推奨されます。
ワークスペースルートに含まれるディレクトリ内のモジュールで go get が実行された場合、go get はワークスペースをほとんど無視しますが、ワークスペースが古すぎる go 行のままである場合に、go.work ファイルを更新して go 行をアップグレードします。
go work を使用した Go バージョンワークスペース要件の管理
前のセクションで述べたように、ワークスペースルート内のディレクトリで実行された go get は、go.work ファイルの go 行を、そのルート内の任意のモジュール以上になるように必要に応じて更新します。しかし、ワークスペースはルートディレクトリ外のモジュールを参照することもできます。これらのディレクトリで go get を実行すると、go.work で宣言された go バージョンが use ディレクティブ内の 1 つ以上のモジュールよりも古い無効なワークスペース構成になる可能性があります。
新しい use ディレクティブを追加するコマンド go work use は、go.work ファイルの go バージョンが既存のすべての use ディレクティブに対して十分新しいことも確認します。go バージョンがモジュールと同期しなくなったワークスペースを更新するには、引数なしで go work use を実行します。
コマンド go work init および go work sync も、必要に応じて go バージョンを更新します。
go.work ファイルから toolchain 行を削除するには、go work edit -toolchain=none を使用します。