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ファイルを指定した時の挙動の変更に気がついて報告したという話でした。