豆知識:この中に1つ、無視されるgo.modがいる!
タイトルは「この中に1人、妹がいる!」のインスパイアです。懐かしいです。
この記事は何
最近ふと知ったGoの仕様に関する紹介記事です。
要点
現在のGoが採用しているモジュール管理において不可欠なgo.mod
ファイルですが、あえて無視するように設計されているケースが1つだけ存在します。それはOSが規定するテンポラルディレクトリ直下のgo.modです。Linuxであれば一般的に/tmp/go.mod
のことですね。
どうしてそんなことに?
こちらのIssueで報告された困りごとを解決するために、この仕様が導入されたようです。
The actual cause is not particularly obvious when you have forgotten there is a bogus go.mod under /tmp from days before.. 🤔
Several tests create temporary build directories under /tmp and run go build, which then finds the go.mod and attempts to fetch unrelated dependencies.
少し補いながら和訳すると
- Goのテスト実行時にはシステムの
tmp
にビルド用のディレクトリを作成し、その中でビルドする。 - テストはパッケージ単位で実行できるため上記ビルドディレクトリ内には
go.mod
が存在しないことがある。(モジュールに慣れすぎてパッケージ単位でのビルドイメージがピンとこない場合は、この記事が参考になります:Using Go Modules) - なにかの拍子で
/tmp/go.mod
が作成された。 - それ以降
tmp
下でビルドすると、ビルドディレクトリ内にgo.mod
が無ければ親ディレクトリに遡っていくため/tmp/go.mod
が参照され、依存関係が不一致になってビルドに失敗する。
これを解消するために/tmp/go.mod
を無視する設計が採用されたようです。例えばGo1.18のソースコードを見ると次の部分がそれに該当します。
※記事にするため適宜改行などを調整しています
} else if search.InDir(modRoot, os.TempDir()) == "." {
// If you create /tmp/go.mod for experimenting,
// then any tests that create work directories under /tmp
// will find it and get modules when they're not expecting them.
// It's a bit of a peculiar thing to disallow but quite mysterious
// when it happens. See golang.org/issue/26708.
fmt.Fprintf(
os.Stderr,
"go: warning: ignoring go.mod in system temp root %v\n",
os.TempDir()
)
一見何のために行っているかわからない処理なので、ガッツリコメントが書いてありますね。
この仕様を鑑みて気をつけることってある?
ほとんどないと思います。
例外としては、例えばコンテナ環境内でビルドを行う際に「せや、ディレクトリ作るのもなんやし、/tmp
直下にビルドしたいモジュールのファイル全部置いたろ!」ってなった時ぐらいですかね…?
おわりに
こういう豆知識って、知るとおもしろいですよね!
Discussion