Carpe Diem

備忘録

Go Toolchainの挙動を確認する【検証編】

概要

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  // これ

役割

  • モジュールがビルドまたは実行される際に使用されるツールチェインのバージョンを制御
    • モジュールが期待するバージョンを明示的に指定

検証環境

こちらに用意した環境のファイルを用意します。

github.com

.
├── 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エラー

こんな感じで簡単に検証ができるので、挙動を確認してみたい方は一度このやり方をやってみてください。