【Golang】Go ModulesのGo依存パッケージ管理
Go 1.11 から導入された Go Modules
Go 1.11 より、Go 依存パッケージの解決のための Go Modules の概念が導入された。簡単に言うと、Go 公式でサポートされた npm
のようなパッケージバージョン管理ツール。
Go プロジェクト配下に見受けられる go.mod
go.sum
と、それにまつわる依存パッケージの話でちょっと混乱してきたので、過去の経緯から一旦整理してまとめてみました。
基本に立ち返って、パッケージのインストール
基本的な Go パッケージのインストールは、 go get
で実施する。
$ go get github.com/hoge/fuga
ローカルに置きたいプロジェクトにせよ依存ライブラリが欲しいにせよ、基本的にはこの方法でパッケージを取得していたし、今もそうする。
従来(Go 1.11 以前)の依存パッケージ管理
Go 1.11 以前では、go get
で取得されたパッケージは $GOPATH
配下に置かれていた。コンパイラは、このディレクトリに配置されたライブラリを参照し、パッケージ間の依存関係を解決していた。
しかし、$GOPATH
配下には最新のパッケージしか管理されず、特定のバージョンのパッケージを使用したいときに依存関係を解決できなかった。そこで Go プロジェクト配下に vendor
というディレクトリを作り、そこに所望のバージョンの依存パッケージを置くことで解決した。Go コンパイラはコンパイル時、 $GOPATH
配下より vendor
配下のパッケージを優先的に見てくれる。この vendor
配下でのパッケージバージョン管理は vendoring
と呼ばれていたようだ。
当時、Go 言語自体がこの vendoring を管理する手段を提供していたわけではなかった。そのため、glideやdepといったサードパーティツールが使用されていた。
Go Modules (Go 1.11 以降)におけるパッケージ管理
Go 1.11 になり、依存パッケージのバージョン管理の機能 Go Modules を公式が提供することになった。元々はVersioned Go Command (vgo)と呼ばれるバージョン管理 Go のプロトタイプがあり、Go 公式が 1.11 より Go Modules としてこれをサポートしたもの。
既に依存パッケージのバージョン管理手段があったとはいえ、公式が直々に提供しているのであればそちらを使用したい。 go fmt
のような Go の思想の前例もあり、新規の Go プロジェクトでは Go Modules による依存パッケージバージョン管理が多く見られる。
Go Modules の概念
Go Modules では、以下の2つのパッケージ管理モードがある。
- GOPATH モード
- module aware モード
これらのモードは環境変数 GO111MODULE
によって切り替えられる(詳細は後述)。
GOPATH モード
Go1.11 と同様のパッケージ管理を提供するモード。
go get
により $GOPATH
配下にパッケージが置かれ、管理およびビルド時の参照はこのディレクトリに対して行われる。管理されるパッケージのバージョンは最新版のみなので、 vendor
によるバージョン管理を要する。
module aware モード
Go Modules の概念に対応したモード。
go get
により取得したパッケージを $GOPATH/pkg/mod
配下に置く。module aware モード中は、Go プロジェクトをどこに配置していようが $GOPATH/pkg/mod
配下のパッケージを参照する。
ちなみに、Go Modules では「モジュール」と呼ばれる概念を使用している。標準ライブラリ以外のパッケージをモジュールと呼ぶが、一方でバージョンによって同じパッケージも別のモジュールとして扱う。
module aware モードでの依存解決と、モジュールの作り方
module aware モードでは、パッケージの管理先ディレクトリが変わるだけではなく、Go プロジェクト(モジュール)が必要とするパッケージのダウンロードも自動化してくれる。
その前に、Go プロジェクトをモジュールとして初期化する必要がある。Go プロジェクトをモジュール化するには、 go mod init
を実行する。
$ go mod init
するとプロジェクトルートに go.mod
ファイルが作成される。ファイルにはモジュール名と、使用する Go ランタイムのバージョンが書かれている。
module github.com/rennnosuke/forblog go 1.13
このプロジェクトに、外部のモジュールを参照するコードを追加し、ビルドしてみよう。
package main import ( "fmt" "rsc.io/quote" ) func main() { fmt.Println(quote.Hello()) }
$ go build hello.go
すると、なんと勝手に必要となる依存モジュールをダウンロードし始める。
go: finding rsc.io/quote v1.5.2 go: downloading rsc.io/quote v1.5.2 go: extracting rsc.io/quote v1.5.2 go: downloading rsc.io/sampler v1.3.0 go: extracting rsc.io/sampler v1.3.0 go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c go: finding rsc.io/sampler v1.3.0 go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
module aware モードでは、ビルドしたモジュールの依存関係から必要な外部モジュールを自動的に割り出し、インストールしてくれる。この依存モジュールは先程の go.mod
に記述される。
module github.com/rennnosuke/forblog go 1.13 require rsc.io/quote v1.5.2
npm
で言うところの package.json
に依存パッケージが記述された状態で npm i
しているようなもの。
Go Modules が導入される前と比較し、格段に依存パッケージを取得しやすくなった。また Go Modules 内ではバージョン別にパッケージが管理されるため、 vendor
も不要になる。
この依存パッケージ解決を繰り返していると、不要なパッケージが溜まってくる。
不要なパッケージを削除するには、 go mod tidy
を実行する。
$ go mod tidy
GOPATH モード・module aware モードの切り替え
先述の通り、GOPATH モードと module aware モードを切り替えるには、GO111MODULE
変数の値を変更する。 GO111MODULE
の値には次の 3 種類がある。
- on
- off
- auto
on
module aware モードを有効にする。
off
GOPATH モードを有効にする。
auto
バージョンによって動作を変える。
Go1.12 以前の場合、カレントディレクトリが $GOPATH
配下であれば GOPATH モードになり、そうでなければ module aware モードになる。
ただし Go1.13 からは、auto
の状態でもカレントディレクトリに go.mod
が存在する場合には module aware モードとして振る舞う。
Go モジュールのチェックサム
Go Module 内に生成される go.sum
には依存モジュールのチェックサムが記録される。このチェックサムを使用して、依存モジュールの内容に変更があったかどうかを検出できる 。これにより、インストールするパッケージが改ざんされたものかどうかをチェックできる。
初回インストール時のパッケージのチェックサム検証はできないが、Go1.13 よりチェックサム DBからチェックサムを参照することで初回パッケージのチェックサムも検証できるようになった。
module aware モードでの go get
module aware モード上で go build
して依存関係解決できるからと言って、 go get
の重要性は依然変わらない。例えば Go プロジェクト内で新たに外部パッケージを使用したい場合、npm install [package]
のように新しく依存関係に追加+パッケージインストールしたくなる。
module aware モードで go get
を実行すると、従来どおりパッケージ(モジュール)はインストールされるが、保存先は module aware モード管理上のディレクトリになる。また go.mod
go.sum
に新しい依存パッケージとして記録される。
Go 1.14 以降における Go Modules への公式見解
Go 1.14 では、モジュールサポートは実稼働で使用できる状態にあると見なされ、すべてのユーザーは他の依存関係管理システムからモジュールに移行することが推奨されます。
来る Go1.14 では、すべての Go ユーザが module aware モードへ移行することが推奨されている。移行が高コストな Go パッケージなどでない限り、Go Modules への移行がどんどん進んでいくものと思われる。
所感、メモ
Go プロジェクトに途中から参画したときに、何も考えずに必要なパッケージがすぐインストールできてビルドできるのは本当にありがたい。
module aware モードでのモジュール管理先ディレクトリは任意に変更可能らしい、が変え方がわからない。要追記。
参考文献
Go 言語の依存モジュール管理ツール Modules の使い方 | MMM ブログ
Go 1.13 に向けて知っておきたい Go Modules とそれを取り巻くエコシステム