Goツールチェーン

はじめに

Go 1.21以降、Goディストリビューションは、goコマンドとバンドルされたGoツールチェーンで構成されています。Goツールチェーンは、標準ライブラリとコンパイラ、アセンブラ、その他のツールです。 goコマンドは、バンドルされたGoツールチェーンと、ローカルのPATHにある、または必要に応じてダウンロードする他のバージョンのGoツールチェーンを使用できます。

使用される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.worktoolchain行は、goコマンドが使用するツールチェーンを決定する際にgo行よりも優先される推奨ツールチェーンを設定します。

go行とtoolchain行は、go.modrequire行が他のモジュールへの依存関係のバージョン要件を指定するのと同じように、モジュールの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.21.0」のように1. *N*.0です。 1. *N*.9のような後のリリースは、多くの場合、パッチリリースと呼ばれます。

1. *N*.0の前に発行されるGo 1. *N* リリース候補は、「1. *N*rc*R*」というバージョン構文を使用します。 Go 1. *N* の最初のリリース候補は、`1.23rc1`のようにバージョン1. *N*rc1です。

構文「1. *N*」は「言語バージョン」と呼ばれます。これは、Go言語と標準ライブラリのそのバージョンを実装するGoリリースの全体的なファミリを示します。

Goバージョンの言語バージョンは、*N* の後のすべてを切り捨てた結果です。1.21、1.21rc2、1.21.3はすべて言語バージョン1.21を実装しています。

Go 1.21.0やGo 1.21rc1などのリリースされたGoツールチェーンは、go versionruntime.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*.0ではなく1. *N* であったため、*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ツールチェーンの名前はgo<i>V</i>で、*V*はベータリリース、リリース候補、またはリリースを示すGoバージョンです。たとえば、go1.21rc1go1.21.0はツールチェーン名です。 go1.21go1.22はそうではありません(最初のリリースはgo1.21.0go1.22.0です)が、go1.20go1.19はそうです。

非標準のツールチェーンは、任意の接尾辞に対してgo<i>V</i>-<i>suffix</i>の形式の名前を使用します。

ツールチェーンは、名前に埋め込まれたバージョン<i>V</i>を比較することによって比較されます(最初のgoを削除し、`-`で始まる接尾辞を破棄します)。たとえば、go1.21.0go1.21.0-customは、順序付けの目的で等しいと比較されます。

モジュールとワークスペースの構成

Goモジュールとワークスペースは、go.modファイルまたはgo.workファイルでバージョン関連の構成を指定します。

go行は、モジュールまたはワークスペースを使用するために必要なGoの最小バージョンを宣言します。互換性の理由から、go行がgo.modファイルから省略されている場合、モジュールには暗黙的なgo 1.16行があると見なされ、go行がgo.workファイルから省略されている場合、ワークスペースには暗黙的なgo 1.18行があると見なされます。

toolchain行は、モジュールまたはワークスペースで使用する推奨ツールチェーンを宣言します。以下の「Goツールチェーンの選択」で説明されているように、デフォルトのツールチェーンのバージョンが推奨ツールチェーンのバージョンよりも小さい場合、goコマンドはそのモジュールまたはワークスペースで操作するときにこの特定のツールチェーンを実行する場合があります。 toolchain行が省略されている場合、モジュールまたはワークスペースには暗黙的なtoolchain go<i>V</i>行があると見なされます。ここで、*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.modgo 1.21.3と言うことはできません。

各モジュールのgo行は、そのモジュールのパッケージをコンパイルするときにコンパイラが適用する言語バージョンを設定します。言語バージョンは、ビルド制約を使用することにより、ファイルごとに変更できます。

たとえば、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環境設定の標準ルールを使用します。

標準のGoツールチェーンでは、$GOROOT/go.envファイルはデフォルトのGOTOOLCHAIN=autoを設定しますが、再パッケージ化されたGoツールチェーンはこの値を変更する場合があります。

$GOROOT/go.envファイルが存在しないか、デフォルトを設定していない場合、goコマンドはGOTOOLCHAIN=localと想定します。

go env GOTOOLCHAINを実行すると、GOTOOLCHAIN設定が出力されます。

Goツールチェーンの選択

起動時に、goコマンドは使用するGoツールチェーンを選択します。 <name><name>+auto、または<name>+pathの形式をとるGOTOOLCHAIN設定を参照します。 GOTOOLCHAIN=autoGOTOOLCHAIN=local+autoの省略形です。同様に、GOTOOLCHAIN=pathGOTOOLCHAIN=local+pathの省略形です。 <name>はデフォルトのGoツールチェーンを設定します。 localはバンドルされたGoツールチェーン(実行されているgoコマンドに付属しているもの)を示し、それ以外の場合は、<name>go1.21.0などの特定のGoツールチェーン名である必要があります。 goコマンドは、デフォルトのGoツールチェーンを実行することを優先します。上記のように、Go 1.21以降、Goツールチェーンは、より新しいGoバージョンを必要とするワークスペースまたはモジュールで実行することを拒否します。代わりに、エラーを報告して終了します。

GOTOOLCHAINlocalに設定されている場合、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コマンドはプロセスの実行可能パス(UnixおよびPlan 9では$PATH、Windowsでは%PATH%)で、指定された名前(たとえば、go1.21.3)のプログラムを検索し、そのプログラムを実行します。そのようなプログラムが見つからない場合、goコマンドは指定されたGoツールチェーンをダウンロードして実行しますGOTOOLCHAINフォーム<name>+pathを使用すると、ダウンロードフォールバックが無効になり、goコマンドは実行可能パスの検索後に停止します。

go versionを実行すると、選択したGoツールチェーンのバージョンが出力されます(選択したツールチェーンのgo versionの実装を実行することにより)。

GOTOOLCHAIN=local go versionを実行すると、バンドルされたGoツールチェーンのバージョンが出力されます。

Goツールチェーンの切り替え

ほとんどのコマンドでは、バージョンの順序付け設定要件により、ワークスペースのgo.workまたはメインモジュールのgo.modには、モジュール依存関係のgo行と少なくとも同じくらい新しいgo行があります。この場合、起動時のツールチェーン選択により、コマンドを完了するのに十分な新しいGoツールチェーンが実行されます。

一部のコマンドは、操作の一部として新しいモジュールバージョンを組み込みます。 go getはメインモジュールに新しいモジュール依存関係を追加します。 go work useはワークスペースに新しいローカルモジュールを追加します。 go work syncは、ワークスペースの作成以降に更新された可能性のあるローカルモジュールとワークスペースを再同期します。 go install package@versiongo 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のリリース ポリシーに準拠したサポートされている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`コマンドはGo 1.28.3を選択します。Go 1.27.9は古すぎるためです。`widget`がGo 1.29以降を必要とする場合、`go`コマンドはGo 1.29rc2を選択します。Go 1.27.9とGo 1.28.3の両方が古すぎるためです。

新しい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`を更新して、起動時に適切なツールチェーンを選択するためです。例外は、`go install package@version`と`go run package@version`形式で、ワークスペースまたはメインモジュールで実行されず、`toolchain`行を書き込むことができません。これらは、新しいツールチェーンに切り替える必要があるたびに切り替えメッセージを出力します。

ツールチェーンのダウンロード

GOTOOLCHAIN=auto または GOTOOLCHAIN=<name>+auto を使用する場合、Go コマンドは必要に応じて新しいツールチェーンをダウンロードします。これらのツールチェーンは、モジュールパス golang.org/toolchain とバージョン v0.0.1-goVERSION.GOOS-GOARCH を持つ特別なモジュールとしてパッケージ化されています。ツールチェーンは他のモジュールと同様にダウンロードされます。つまり、ツールチェーンのダウンロードは GOPROXY を設定することでプロキシでき、Go チェックサムデータベースによってチェックサムがチェックされます。使用される特定のツールチェーンは、システム自身のデフォルトのツールチェーンと、ローカルのオペレーティングシステムとアーキテクチャ(GOOS と GOARCH)に依存するため、ツールチェーンモジュールのチェックサムを go.sum に書き込むことは現実的ではありません。代わりに、GOSUMDB=off の場合、検証が不足しているため、ツールチェーンのダウンロードは失敗します。 GOPRIVATEGONOSUMDB のパターンは、ツールチェーンのダウンロードには適用されません。

go get を使用した Go バージョンのモジュール要件の管理

一般的に、go コマンドは go 行と toolchain 行を、メインモジュールのバージョン付きツールチェーン依存関係を宣言するものとして扱います。 go get コマンドは、バージョン付きモジュール依存関係を指定する require 行を管理するのと同じように、これらの行を管理できます。

たとえば、go get go@1.22.1 toolchain@1.24rc1 は、メインモジュールの go.mod ファイルを go 1.22.1toolchain go1.24rc1 に変更します。

go コマンドは、go 依存関係には、Go バージョンが同じかそれ以上の toolchain 依存関係が必要であることを理解しています。

例を続けると、後の go get go@1.25.0 は、ツールチェーンも go1.25.0 に更新します。ツールチェーンが go 行と完全に一致する場合、省略して暗黙的に指定できるため、この go gettoolchain 行を削除します。

ダウングレードする場合にも同じ要件が逆方向に適用されます。 go.modgo 1.22.1toolchain go1.24rc1 で始まる場合、go get toolchain@go1.22.9toolchain 行のみを更新しますが、go get toolchain@go1.21.3go 行も go 1.21.3 にダウングレードします。その結果、toolchain 行のない go 1.21.3 のみが残ります。

特殊な形式 toolchain@none は、go get toolchain@nonego get go@1.25.0 toolchain@none のように、toolchain 行を削除することを意味します。

go コマンドは、go および toolchain 依存関係とクエリに対するバージョン構文を理解します。

たとえば、go get example.com/widget@v1.2example.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 と互換性のあるバージョンにダウングレードするか、要件を完全に削除します。

Go 1.21 より前は、モジュールを新しい Go バージョン(たとえば、Go 1.22)に更新するための推奨される方法は go mod tidy -go=1.22 でした。これは、go 行が更新されると同時に、Go 1.22 に固有の調整が 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 を使用します。