はじめに
TIG真野です。
Go 1.16連載の2つ目となるこの記事では、Go 1.16で機能追加された go install
について説明します。
go installの新機能
Go 1.16から go install
に新機能が追加されました。go install
自体は従来から存在しているので全く新しいコマンドが増えたわけではなく、機能拡張されたイメージです。
go install
の機能拡張部分ですが簡単に言うと、バージョン指定できるようになりました。言ってみればそれだけです。嬉しいこととして、それによってgo.mod
の書き換え無しにツールなどのインストールを行いやすくなりました。ちなみに、インストールとはコードをコンパイルして、$GOPATH/bin
とか$HOME/go/bin
にビルドしたバイナリを配備してくれることです。
従来はgo get
でツールのインストールも行えていましたが、同時にgo.mod
も書き換わってしまいました。メインで開発するモジュールで利用するライブラリならgo.mod
に追記されることが自然ですが、例えばGoのLanguage Serverであるgopls
や、stringer
といった開発系のコマンドラインツールの場合は少し困りました。
どういうことかと言うと、メインで開発するモジュール本体のgo.mod
で、例えばgo get golang.org/x/tools/cmd/stringer
でインストールすると一時的に go.mod
に追加されてしまうのです。もちろん、コードの中にはimportされていないため、go mod tidy
すると消すことができますが、新規参画者の最初の環境構築で手順を間違えると不要な差分が出てきて少し手間でした。参画タイミングによって新しいバージョンが出たりすると、go get
でgo.mod
のバージョンが書き換わるのもまた問題でした。また、逆に go mod tidy
するとgo.mod
から削除されますが、つまり開発系ツール自体のバージョン管理ができなくなる問題もありました。そちらについては後述します。
今回追加された go install
を用いればこういったストレスからは開放されるかと思います。なんとなく go get
の機能が分割され、今後はGo Module追加編集のためのgo get
、ツールなどのバイナリインストールのgo install
と住み分けることができそうです。
利用方法
go install example.com/cmd@v1.0.0
の形式で利用可能です。go get
と同じ指定方法ですね。
例えば、stringerであれば
go get golang.org/x/tools/cmd/stringer@v0.1.0
です。バージョンは必須とのこと。最新で良い場合は@latest
をつけます。
動かしてみる
Go 1.16のRelease Candidate1でgo install
を動かしてみます。
>go version |
適当なフォルダで go mod init
して、go get golang.org/x/tools/cmd/stringer@v0.1.0
と go install golang.org/x/tools/cmd/stringer@v0.1.0
の実行結果を比較してみます。
>go get golang.org/x/tools/cmd/stringer@v0.1.0 |
Go 1.16だとまだ go get
でインストールもできるようですね(将来的に消える可能性があるので注意です)
続いて、go install
で動かしてみます。
>go install golang.org/x/tools/cmd/stringer@v0.1.0 |
リリースノート通り、go.mod
への副作用はありませんでした。
ローカルリポジトリに対してのgo install
こちらは従来どおり、そのまま利用可能です。
package main |
以下のような適当なmainパッケージなファイルを作成してinstallします。
$ go install mycmd.go |
また、巷では、toolsフォルダをつくって、そこでgo mod init tools
して、上記の記事のようなブランクインポートする流派もあります。こうすると開発しているモジュールが依存するパッケージと、ツールのバージョン別に管理できるプラクティスとして一定の広がりがあったと思います。
どちらにしても開発ツールのバージョンをgo.mod
に記載し、そのディレクトリでgo install golang.org/x/tools/cmd/stringer
などとしていました。複数あるとそのまま複数個installコマンドを愚直に打つか、cat tools.go | grep _ | awk -F'"' '{print $2}' | xargs -tI % go install %
などでシェル技が炸裂していました。
Go 1.16での変化ですが、RC1時点だと go get
でインストールはまだ行ってくれます。しかし将来的に使えなくなる可能性があるので、素直に go install
を使いましょう。従来のgo install
はバージョン指定ができなかったため、わざわざGo Module管理するためにハックを繰り返していましたが、Go 1.16だとそもそも不要です。
素直に make install
でセットアップするが正解になる気がします。
|
このあたりのプラクティスは、Go WikiのHow can I track tool dependencies for a module? がどう変わるかをウォッチしていこうと思います(多分、変わるはず..)
//go:generate
ディレクティブ
Go Modules が導入されてから、公開されている Go 製のツールは go run によるダウンロード・ビルド・実行が一度にできるようになっていたのですが、Go1.16だとgo.mod
が自動で更新されない影響か、//go:generate go run golang.org/x/tools/cmd/stringer -type=Pill
でインストール無しで go generate
するだけでコード生成するハックが使えなくなりました。
package generate |
上記のようにすると、各開発者が事前準備無しにgo generate
さえ実行するだけで済んだのですが、Go1.16だとこうなります。
>go generate |
同じ開発体験を守りたいなら、複数行に記載することになると思います。
package generate |
>go generate |
無事生成はできました。//go:generate
ディレクティブに go run
コマンドを書くのはちょっとしたハック感があって好きだったのですが、初見では混乱するので消えて良かったのかもしれませんね。
余談
go build
とかgo test
で自動的にgo.mod
が更新されない変わりに、go mod tidy
してねってメッセージがでるようなりました。どのタイミングで表示してくれるのか細かくは良く分かりませんが、気がついたらバージョンを上げると良いかと思います。
まとめ
go install
でバージョンを指定ができるようになった- いくつかのハックが陳腐化したり、使えなくなったが、試行錯誤した経験は我々の中にずっと残り続ける