Skip to content

toolディレクティブの依存でgoディレクティブが上がってしまう問題の対策

go.modgo ディレクティブは下限となる言語バージョンを意味するので、メインモジュールは、それが依存するモジュールの下限を満たす必要がある。なので例えば exp モジュールが 1.24.0 を宣言していれば、少なくともメインモジュールの go ディレクティブはそれ以上を指定しなければならない。この挙動は、一般的なライブラリであればコミュニティ全体に互換性を維持する力が作用していて公式サポートバージョンは維持してくれるので、問題になることは多くない。

しかし tool ディレクティブとなると話は変わってくる。tool の場合、他者から依存されるものではないためビルドができれば後方互換を維持する習慣がない。そうなると結構な気軽さで go ディレクティブを更新するが、tool ディレクティブは全部まとめて go ディレクティブの下限を決めるので、ツールの宣言に影響されて上がってしまうことがある。

じゃあどうするか。ほとんどの go コマンドは -modfile= オプションを受け付けるので、これでツール部分を分離させて、必要な場面で切り替えるといい。

Terminal window
go get -modfile=tool.mod golang.org/x/tools/cmd/stringer@latest
go mod tidy -modfile=tool.go
go tool -modfile=tool.mod stringer

setup-go では、キャッシュのため以下のように。

- uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache-dependency-path: |
go.sum
tool.sum

ところで、go generate で実行するコマンドを書くとき、

//go:generate go tool -modfile=../tool.mod xxx

のように相対パスを書くことになるが、これを親ディレクトリから実行するとカレントディレクトリはどうなるのか不思議に思った。結論としては go generate が内部で chdir(2) しているようで、どこから実行してもファイル位置からの相対パスで書けばいい。

次の資料がよくまとまっていた。