GOPATH に(可能な限り)依存しない Go 開発環境(Go 1.15 版)
2018 年ごろまでの Go に対する不満として以下のようなものがありました。
-
$GOPATH/src
配下でしか開発できない
これは、import された package の探索先として $GOPATH/src
が使用されていたことに起因します。
つまりどこかから呼び出される package を書きたい場合は $GOPATH/src
配下に存在しなければ探索できない、そのため実質 $GOPATH/src
配下でしか開発できないということでした。
しかし 2018 年末にリリースされた Go 1.11 によりこの不満は解決されることとなります。
Go 1.11 で導入された Go modules という新たな仕組みを有効にしておくと package 探索先として $GOPATH/src が使わなくなったのです。
その代わりに例えば github.com/go-sql-driver/mysql
という package を import する場合は github.com
に対して go-sql-driver/mysql
というリポジトリが存在するかを尋ね、存在する場合自動で取得してくれるという挙動になりました。
Go modules 自体の説明は本記事の主題とするところではないので、他に譲ります。
Go modules により先の問題は解決されたものの、これにより私は Go 1.11 から環境変数 GOPATH への依存が完全になくなったという誤解をしてしまいました。
この記事ではそのときの私に向け、Go modules 下の GOPATH
が担う役割とその役割を可能な限り GOPATH
から排除するための設定を説明することが目的です。
GOPATH
が担う役割
GOPATH
配下に存在するディレクトリは以下です。
src
bin
pkg/$GOOS_$GOARCH
pkg/mod
pkg/sumdb
src
$GOPATH/src
ディレクトリは Go のソースコードが配置され、先に述べたとおり Go modules を無効にしている状態 (GOPATH mode と呼ぶ) では import された package の探索先として使われます。
このディレクトリは Go modules を利用することで不要になります。
具体的には環境変数 GO111MODULE=on
と設定することで、$GOPATH/src
から開放されます。
bin
$GOPATH/bin
ディレクトリは Go コマンドによりインストールされた実行ファイルを配置するためのディレクトリです。
この実行ファイルを配置するためのディレクトリは GOBIN
という環境変数によって変更することができます。
そのため、例えば ~/bin
を使いたい場合は GOBIN=$HOME/bin
と指定することにより $GOPATH/bin
から開放されます。
pkg/$GOOS_$GOARCH
$GOPATH/pkg/$GOOS_$GOARCH
ディレクトリには Go コマンドによりインストールされた Binary-Only package が配置されます。
Binary-Only package とは package のコンパイルに使用したソースコードを含まずバイナリ形式で package を配布する仕組みでした。
でした。と書いたのは、この機能は Go 1.13 から廃止されてしまったからです。
私もこの機能は利用したことがないので詳細は分かりません。
Go 1.13 で廃止されているので、Go 1.13 以降を利用することで $GOPATH/pkg/$GOOS_$GOARCH
から開放されます。
cf. Binary-Only Packages
cf. Go 1.13 Release Notes
pkg/mod
このディレクトリは Go modules を有効にしている場合のみ利用されます。
Go modules が無効な状態(GOPATH mode)であれば、ダウンロードされた package は $GOPATH/src
に配置されていました。
それに対して Go modules が有効な状態(module-aware mode と呼ぶ)では、ダウンロードされた package(正確には module という名前が付けられている) が $GOPATH/pkg/mod
に配置されます。
さらにこれら module について問い合わせた結果のキャッシュも保持されています。
go get
コマンドなどはこのディレクトリを参照するものの、あくまでキャッシュという扱いなので、あればそれを使う、無ければダウンロードしてくるという挙動です。
そのためこのディレクトリ内で作業しなければならないといった制約は無くなったのです。
さらにこのディレクトリは 2020/09 時点最新の Go 1.15 にて GOMODCACHE
という環境変数が用意され、位置を変更できるようになりました。
そのため、例えば ~/.cache/go_mod
を使いたい場合は GOMODCACHE=$HOME/.cache/go_mod
と指定することにより $GOPATH/pkg/mod
から開放されます。
pkg/gosum
Go 1.13 より Go module proxy と Go checksum database という仕組みが導入されました。
これらは Go modules がリポジトリをホスティングしているサービスに依存しているという問題や悪意ある攻撃者により module をすりかえられるかもしれないという問題に対処するために用意されました。
これらの詳細はさておき、ここで注意すべきは、go get
などで module を取得する際に module proxy に問い合わせることで module の情報を取得し、checksum database に問い合わせることにより module の完全性を確認するという点です。
pkg/gosum
は checksum database へ問い合わせた結果のキャッシュが配置されるディレクトリです。
module proxy へ問い合わせた結果のキャッシュは pkg/mod/cache
配下に保持されるので、これは先の GOMODCACHE
環境変数にて制御可能です。
残念ながら、この pkg/gosum
ディレクトリを制御するための方法は Go 1.15 時点存在しません。(私の探し方が甘いだけだったらすいません。)
cf. Proposal: Secure the Public Go Module Ecosystem
cf. Issue: cmd/go: add GOMODCACHE
まとめ
Go 1.11 から導入された Go modules により、Go の開発が $GOPATH/src
の外でもできるようになりました。
あくまで GOPATH
環境変数の package 探索先としての機能が使われなくなっただけであり、他の用途で Go 1.15 現在も利用されています。
以下のように設定すれば $GOPATH/pkg/gosum
以外の $GOPATH
配下のディレクトリは他の位置に移動させることができます。
指定したディレクトリは私の好みによるものなので、みなさんの好きなディレクトリを指定してください。
export GO111MODULE=on # Go 1.11 から利用可能
export GOBIN=$HOME/bin
export GOMODCACHE=$HOME/.cache/go_mod # Go 1.15 から利用可能
今後 Issue: cmd/go: default to GO111MODULE=on で GOPATH mode(GO111MODULE=off
) の廃止が検討されています。
が、このコメントにもあるように、GOPATH
環境変数自体はしばらく生き続けるんだろうなぁと思います。
Discussion