Go Modulesとマルチモジュール構成でGo Homeする方法
Go Modulesでマルチモジュールにする方法がわからなくて調べました。発端は単にgo.modがある別モジュールのパッケージをインポートしようとしても出来なかったことです。そこで、Go Modulesでマルチモジュールを実現するためのシナリオを説明してみたいと思います。
TL;DR
- Go Modulesは便利なので使っていこう
- Go Modulesでマルチモジュール構成にする場合はgo.modファイルで
replaceディレクティブを使おう - マルチモジュール構成の採用には慎重になろう
Go Modulesとは
とりあえず、Go Modules is 何?という方の為に簡単に説明します。ご存知の方はこの節を飛ばしてください。
Go ModulesはGo 1.11から試験的に導入され、Go 1.13からデフォルトで有効になる予定の新しいパッケージ依存関係の管理方法です。使ってみた実感としてはすでに充分実用的なので新規にプロジェクトを作成する場合はGo Modulesを使って作成することをオススメします。Go 1.12でGo Modulesを有効にするためには、GOPATH以外のパスで作業をするか以下で環境変数を設定します。
1 | |
この記事ではGo 1.12の前提で解説します。
Go Modulesで管理を始める
基本はディレクトリを作成してgo mod init <モジュール名>で始められます。
1 | |
go.modというファイルが作成されています。これが依存関係を管理するファイルになります。
1 | |
まずは基本のおはようの挨拶から
早速ですが、基本どおりHello Worldから初めて見ます。ただし、依存関係を入れるために go-figureを利用して挨拶をしてみます。ソースコードは以下の通りです。
1 | |
go buildをすると依存関係があるパッケージがダウンロードされて、ビルドされます。事前にgo getする必要がないので、これだけでもGo Modulesの良さがわかります。./go-multi-modulesで実行して無事挨拶ができれば成功です。
1 | |
go.modファイルを見てみるとrequireの行が追加されて依存関係が追跡されているのが分かります。
1 | |
また、go.sumというファイルも生成されます。依存関係の管理はgo.modだけでもできますが、go.sumは検査用に必要なようです。詳しくは ここを参照してください。
1 | |
おはようの挨拶をパッケージにしてみる
さて、挨拶は毎日するものです。せっかくなので再利用可能なようにパッケージとして分離してみます。pkgディレクトリを作成し[^1]、その下にhello-worldディレクトリを作成して、その下にhello-world.goファイルを作成します。ディレクトリ構成は以下の通りです。今回はhelloworldというパッケージを作成します。
1 | |
hello-world.goファイルの中身は以下の通りです。
1 | |
main.goファイルは以下のように書き換えます。
1 | |
go buildでビルドして./go-multi-modulesで実行して同じように挨拶ができたら成功です。
[^1]: pkgディレクトリはGo Modulesを使う上で必須ではありませんが、ここではGoの標準レイアウトを採用しています。
Go Homeしようとして失敗する
さて、挨拶も済んだのでもう用はありません。帰宅したくなってきたとします。ただし、帰宅時間まで細かく管理されたくないので別モジュールで管理することを考えます。この場合、pkgディレクトリ配下にgo-homeディレクトリを作成して、go-homeディレクトリに移動してからgo mod init gohomeを実行します。
ディレクトリ構成は以下のようになります。
1 | |
go-home配下のgo.modは以下のようになります。初期化しただけなのでrequireはありません。
1 | |
home.goは以下のようになります。
1 | |
main.goは以下のように書き換えます。
1 | |
これをトップディレクトリ(go-multi-modulesディレクトリ)でgo buildでビルドしようとしたところ以下のようなエラーが出てうまくいきませんでした。どうやらモジュールの読み込みに失敗したようです。
1 | |
replaceのおかげでGo Homeに成功する
解決方法は簡単で親のgo.modに以下のreplaceディレクティブを記述することでした。
replace go-multi-modules/pkg/go-home => ./pkg/go-home
replaceディレクティブを記述してgo buildをするとビルドが成功します。
以下はgo build後のgo.modです。依存関係(require)が追加されています。
1 | |
さて、ビルドできたら./go-multi-modulesで実行してみましょう。一瞬Hello Worldが表示されてその後Go Home!が実行されます。
我々はようやく成し遂げたのです(笑)。
なぜ、マルチモジュール化したかったのか?
さて、ここまででマルチモジュール化の方法が分かったわけですが、問題の発端のなぜ自分がマルチプロジェクトにしたかったのかをまだ説明していませんでした。
理由としてはC言語のライブラリをビルドしてcgoで呼び出すモジュールを書いたのですが、makeでビルドする必要があったのでgitのサブモジュールでローカルに取り込もうとして、必然的にマルチモジュール構成になりました。ただ本家のFAQでは一つのリポジトリに一つのモジュールをススメているので、一般的にはマルチモジュールの採用には慎重になったほうがいいと思われます。
まとめ
本記事ではGo Modulesにおける「マルチモジュール構成」に焦点を当てて、以下についてストーリ仕立てで解説しました。
- Go Modulesを使って依存関係を管理する方法
- パッケージに分割して呼び出す方法
- マルチモジュール構成にする方法
- ただし安易にマルチモジュール構成にしないほうがよい
- Go Home! する方法[^2]
またこの記事を書くために作成したコードは以下に置きました。
この記事がGo Modulesを使ってモジュール管理を始めようという方、マルチモジュールで躓いた方の参考になれば幸いです。
[^2]: Go Homeはネタなので優しくスルーして頂けると幸いです。




