この記事はGo Advent Calendar 2020 16日目の代打記事です。奇しくも16日目にGo1.16の話をすることになりました。
【追記】タイトル改題しました
状況が落ち着いてだいぶ経ったのと、未だに多くの方にこの記事を見ていただけていることから、Go1.16での変更というより、今を生きる私達がどうすればいいか、という点にフォーカスしたタイトルに改題しました。本文に変更はありません。一応注記すると、go get が廃止になったわけではなく、普段の開発フローで使うことはまずなくなった、という意味です。(一通り読んでいただければお分かりいただけるかと。)
【追記】Go1.18について
ついに待望のGo1.18がリリースされましたね! https://go.dev/doc/go1.18#go-command
そして予告通り go get によるインストール機能は削除されました。どうしても従来のように go get でビルドとインストールを行いたい場合、GO111MODULE
環境変数を off
にしてGOPATHモードにすることで可能です。
【追記】Go1.17について
Go1.17がリリースされました。 https://golang.org/doc/go1.17#go-get
Go1.17では、go get によるツールのインストールに警告が表示されるようになります。Go1.18 にて、go get によるツールのインストール機能が削除される予定です。(当初は1.17で削除される予定でしたが、変更されました。)
はじめに
Go1.16では、Modulesに関する様々なアップデートが入ります。cf. https://tip.golang.org/doc/go1.16#tools
- ツールのグローバルインストールを簡単にするため、
go install
に新たな機能が追加されました。今後は「バイナリのビルドとインストールのためのgo install
」、「go.mod
編集のためのgo get
」と役割が整理されていくことになりました。(issueはこちら。) -
GO111MODULE
はデフォルトでon、つまり常にModuleモードが有効になりました。GOPATHモードにお別れを。 -
go build
やgo test
で自動的にgo.mod
が更新されることがなくなりました。go.mod
の編集はgo get
,go mod tidy
, あるいは手作業で行います。
この記事では、Go1.16以降のgo get
/ go install
の使い方、抑えておきたいポイントを解説します。ちなみに、以下はすべてGOPATHモードではなくModuleモード前提で解説しています。(でないと複雑になりすぎるので)
抑えておきたいポイント
- 基本的に、ツールのグローバルインストールには
go install <package>@<version>
を使用します。- 例:
go install golang.org/x/tools/gopls@latest
- スクリプトなどに書いていた方はごめんなさい、修正をお勧めします。
- 例:
-
go get
のバイナリインストールの機能は今後のバージョンで削除される予定です。 -
go get
はgo.mod
に依存性を追記するためだけのコマンドとして整理されていきますが、go.mod
の編集にはgo get
以外の方法も用意されているので、go get
を使う機会は今後少なくなっていきそうです。
Go1.16で解決されるツールのインストール問題
今までGoでグローバル ($GOPATH/bin
) にツールをインストールするにはお馴染みの go get
コマンドが使われてきましたが、一つ問題を抱えていました。go get
は go.mod
を編集する役割も兼ねているため、go.mod
を触らずにツールだけをインストールするには「go.mod
のあるディレクトリを抜けて」「ツール側の go.mod
を有効にし」go get
する、という手順が必要でした。一つにまとめると以下のようになります。
$ cd $(mktemp -d); GO111MODULE=on go get golang.org/x/tools/gopls
流石にインストール一つにこんな手間は掛けたくないし、何よりModulesについてよく知らずに go get
を行い不本意な go.mod
の更新を行ってしまう事故が絶えませんでした。(ソースは筆者)
というわけで、Go1.16からは以下のようになります。
$ go install golang.org/x/tools/gopls@latest
とてもすっきりしましたね。
実はこの go install <package>@<version>
という書式がGo1.16で新たに導入されたものです。この書式では、Module配下であろうとなかろうと、一貫して指定したversionを $GOPATH/bin
にインストールします。
Go1.16では GO111MODULE
はデフォルトでonになっているし、go install
は go.mod
を編集しなくなるため、もろもろの事故が起こることもなくなりました。
注意
-
@version
つきでインストールできるのはmain packageのみです。非main packageはこの書式の対象ではありません。
補足: version指定なしの go install <package>
について
- Module外で
@version
なしのgo install <package>
は出来ません。 - Module配下では、
@version
なしのインストールも可能(go.mod
のバージョンが反映される)ですが、main packageをgo.mod
に記載しておくにはひと手間必要なので、Module配下であろうとgo install <package>@<version>
を行うのがシンプルでよいかと思います。- 非main packageのインストールについては、次の項目をご覧ください。
go install
のその他の機能について
go install
のその他の機能、つまり、
- 作業ディレクトリをビルドして
$GOPATH/bin
に配置する機能 - 非main packageをビルドしてキャッシュする機能(Module配下で、version指定せずに
go install <package>
)
については、従来のまま変わりありません。これらは無くても生きていける代物ではありますが、たまに思い出すと便利かもしれません。
go get
, go.mod
について
一方の go get
は、バイナリインストールの役割を go install
に譲り、go.mod
を編集するためだけのコマンドとして整理されていきます。Go1.16より後のリリース(Go1.17予定→Go1.18予定に変更)では、go get
によるバイナリインストールの機能は削除され、go get
はすべて go get -d
相当の、ソースをダウンロードし go.mod
に追記するだけの挙動になる予定です。
go.mod
を編集する方法
Go1.16では他にも、go build
や go test
で自動的に go.mod
が編集されないという挙動の変更がありました。これらを踏まえて、Go1.16で go.mod
を扱う方法は以下の通りになります。
A) コードにimport文を書いてから go.mod
に反映する方法
-
go get # 引数なし
- 新規モジュール追加のみ
-
go mod tidy
- 不要モジュールの削除と新規モジュールの追加を行ってくれる
B) importされていないモジュールを go.mod
に追加する方法
go get <package>[@<version>]
- 手作業で
go.mod
を編集
4つ挙げましたが、実際のところ go mod tidy
がすべて賄っているので、go mod tidy
一本で行ってもよさそうです。
Go1.15からの変更点
先に述べている通り、go build
などによる go.mod
の自動編集の機能はGo1.16から無効になるため、Go1.15までのユーザーは、go.mod
が変更されるのに期待して go build
するとあれっ?となるかもしれません。go mod tidy
しておきましょう。
また、Go1.18以降で go get
のバイナリインストールの機能が削除されるため、それまでに各種手順書やスクリプトを修正する必要がありそうです。
gopls
もv0.6.0からGo1.16に追従して go.mod
の自動編集を行わなくなる変更が入っています。順次開発フローに関しても、新しいModulesに寄せて整っていくのではないかと思われます。
まとめ
ツール周りで一部非互換な変更が入りますが、Go1.16からのModulesは大幅に簡潔かつハマりどころも少なくなっているため、より初心者には勧めやすくなったのではないでしょうか。Goを布教したい気持ちが強い筆者としては、ハマりどころが少なくなると非常にやりやすくなるし、布教のモチベも高まります。
他にも embed
やら io/fs
やら目玉機能が目白押しのGo1.16が待ち遠しいところです。リリース予定は来年の2月頃です。