Go 1.18 がリリースされて一か月程経ちました。
先日 go run
を (go generate
経由で) 使っているコードの挙動を見ていたら、モジュール周りの挙動が Go 1.17 と異なることに気が付きました。
Go 1.16 以降、go get
や go mod tidy
のような一部のコマンドを除くと、go.mod
に足りない依存パッケージがあるときはエラーになります。
go run
やgo test
などでもgo.mod
を更新したい場合は、-mod=mod
というフラグを指定します。
go run
は、Goのファイルのコンパイルと実行を行うコマンドです。
パッケージを引数として利用されることが多いコマンドですが、Goのファイルを指定して実行することもできます。
❯ cat main.go package main func main() { println("Hello, world!") } ❯ cat go.mod module tmp go 1.18 ❯ go run . Hello, world! ❯ go run main.go Hello, world!
Goのファイルを指定して実行する場合はcommand-line-arguments
パッケージという特殊な名前が付けられています。
これはほとんどドキュメントに記述されていませんが、go list
のようなコマンドで確認することができます。
❯ go list . tmp ❯ go list main.go command-line-arguments
さて、コードが依存しているパッケージがgo.mod
にない場合はどうなるでしょうか。
go run
コマンドはデフォルトではgo.mod
を更新しないので、依存パッケージが足りない場合はエラーになります。
❯ cat main.go package main import "golang.org/x/sys/unix" func main() { println(unix.Getpid()) } ❯ cat go.mod module tmp go 1.18 ❯ go run . main.go:3:8: no required module provides package golang.org/x/sys/unix; to add it: go get golang.org/x/sys/unix ❯ go run main.go main.go:3:8: no required module provides package golang.org/x/sys/unix; to add it: go get golang.org/x/sys/unix
では -mod=mod
をつけるとどうなるでしょうか。
足りない依存をgo.mod
やgo.sum
に追加するフラグですので、go.mod
にgolang.org/x/sys/unix
パッケージが追加されます。
❯ go run -mod=mod . go: finding module for package golang.org/x/sys/unix go: found golang.org/x/sys/unix in golang.org/x/sys v0.0.0-20220412211240-33da011f77ad 10664 ❯ cat go.mod module tmp go 1.18 require golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
ファイルを指定した時も同じ挙動を期待しますよね。 しかし、Go 1.18.1の挙動は以下のようになります。
❯ cat go.mod module tmp go 1.18 ❯ go run -mod=mod main.go go: finding module for package golang.org/x/sys/unix 10820 ❯ cat go.mod module tmp go 1.18
あれれ、go.mod
が更新されませんね。
足りない依存パッケージの検索やダウンロードはされ、コードは実行されましたが、go.mod
は更新されません。
これはgo build
など、他のコマンドも同じ挙動になります。
実は Go 1.17 ではこの挙動ではありませんでした。
ファイルを指定した場合も-mod=mod
を指定すればgo.mod
が更新されていました。
この挙動に依存していたわけではなく、違いに気がついたのは偶然でした (Dockerイメージをpullしておらず、ホストマシンのGoとバージョンがずれていた)。
Go 1.18のリリースノートやマニュアルを確認しましたが、いずれにもこの挙動に関する記載はありません。
たしかにcommand-line-arguments
パッケージは特殊な立ち位置で、特にモジュールとの兼ね合いは難しくなっています。
しかし、ユーザーに影響がある挙動の変更ならば、リリースノートに書いて欲しいですよね。
そういう気持ちを込めて、バグトラッカーに報告してみました。
github.com
無事、リグレッションの判断がされたので、Go 1.18へのバックポートもされるようです。
すぐに修正CLが投稿されました。
go run
コマンドで-mod=mod
とGoファイルを指定した時の挙動の変更に気がついて報告したという話でした。