GOPATH に(可能な限り)依存しない Go 開発環境(Go 1.15 版)

6 min読了の目安(約3900字TECH技術記事
Likes54

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 から開放されます。

cf. Go 1.15 Release Notes

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 環境変数自体はしばらく生き続けるんだろうなぁと思います。