Go 1.16 中關於 go get 和 go install 你需要注意的地方

張晉濤發表於2020-12-21

Go (golang) 已於 18 日釋出了 1.16 beta1 版本,至此其主體功能已經基本確定。我看大多數人都在關注 Go 在蘋果(Apple) M1 上的支援,甚至 Go 官方部落格中也有一篇專門的說明 Go on ARM and Beyond ,來介紹 Go 在此方面的支援。

我就不湊熱鬧了,我來聊聊 Go 1.16 中關於 go getgo install 你需要注意的地方。

目前 Docker 官方映象尚未釋出,我是本地構建了個映象來使用。

(MoeLove) ➜  go version
go version go1.16beta1 linux/amd64

概覽

Go 1.16 中包含著大量的 Modules 相關的更新,詳細內容可直接檢視其 Release Note。整體而言,包含以下要點:

  • GO111MODULE 預設為 on ,如果要恢復到之前的行為,則需要將 GO111MODULE 設定為 auto ,這樣差不多意味著 GOPATH 模式要逐步淡出人們的視野了;
  • go install 命令可以接受一個版本字尾了,(例如,go install sigs.k8s.io/kind@v0.9.0),並且它是在模組感知的模式下執行,可忽略當前目錄或上層目錄的 go.mod 檔案。這對於在不影響主模組依賴的情況下,安裝二進位制很方便;
  • 在將來,go install 被設計為“用於構建和安裝二進位制檔案”, go get 則被設計為 “用於編輯 go.mod 變更依賴”,並且使用時,應該與 -d 引數共用,在將來版本中 -d 可能會預設啟用;
  • go buildgo test 預設情況下不再修改 go.modgo.sum。可通過 go mod tidygo get 或者手動完成;

總結而言,關於 go installgo get 必須要注意的是:

  • 基本上 go install <package>@<version> 是用於命令的全域性安裝:

    • 例如:go install sigs.k8s.io/kind@v0.9.0;
  • go get 安裝二進位制的功能,後續版本將會刪除;
  • go get 主要被設計為修改 go.mod 追加依賴之類的,但還存在類似 go mod tidy 之類的命令,所以使用頻率可能不會很高;

Go 1.16 中已解決的工具安裝問題

到目前為止,Go 一直使用 go get 命令,將我們需要的工具安裝到 $GOPATH/bin 目錄下,但這種方式存在一個很嚴重的問題。go get 由於具備更改 go.mod 檔案的能力,因此我們 必須要避免執行 go get 命令時,讓它接觸到我們的 go.mod 檔案 ,否則它會將我們安裝的工具作為一個依賴。

目前的解決方案通常是:

(MoeLove) ➜  cd $(mktemp -d); GO111MODULE=on go get sigs.k8s.io/kind@v0.9.0

自 1.16 開始,我們可以直接使用下面的方式:

(MoeLove) ➜  go install sigs.k8s.io/kind@v0.9.0

非常的簡單直觀。需要注意的是 go install <package>@<version> 是從 1.16 開始增加的,無論你當前是否在一個模組下,此命令都會在 $GOPATH/bin 下安裝指定版本的工具。

此外由於 Go 1.16 中 GO111MODULE 預設是開啟的,go install 不會修改 go.mod 之類的檔案,不會造成任何意外。

注意:

@version 只能安裝主軟體包。非主程式包不受此格式約束。

關於不帶 @versiongo install

  • 在模組外,不帶 @version 是無法安裝的,會有如下錯誤:
(MoeLove) ➜  go install  -v sigs.k8s.io/kind
go install: version is required when current directory is not in a module
        Try 'go install sigs.k8s.io/kind@latest' to install the latest version
  • 如果你在模組目錄中,並且你不帶 @version 執行安裝的話,只能安裝 go.mod 中已經包含的版本。並且不能安裝未出現在 go.mod 中的包。
(MoeLove) ➜  mkdir -p /go/src/github.com/moelove/iris
(MoeLove) ➜  cd /go/src/github.com/moelove/iris
# 初始化模組
(MoeLove) ➜  /go/src/github.com/moelove/iris go mod init
go: creating new go.mod: module github.com/moelove/iris
(MoeLove) ➜  /go/src/github.com/moelove/iris cat go.mod 
module github.com/moelove/iris

go 1.16


# 不帶 @version 無法安裝
(MoeLove) ➜  /go/src/github.com/moelove/iris go install -v sigs.k8s.io/kind
no required module provides package sigs.k8s.io/kind; try 'go get -d sigs.k8s.io/kind' to add it

# 用 go get -d 下載
(MoeLove) ➜  /go/src/github.com/moelove/iris go get -d sigs.k8s.io/kind
go get: added sigs.k8s.io/kind v0.9.0

# 可以看到已經被新增到了模組依賴中
(MoeLove) ➜  /go/src/github.com/moelove/iris cat go.mod 
module github.com/moelove/iris

go 1.16

require sigs.k8s.io/kind v0.9.0 // indirect

# 刪除本地的 kind 工具
(MoeLove) ➜  /go/src/github.com/moelove/iris which kind
/go/bin/kind
(MoeLove) ➜  /go/src/github.com/moelove/iris rm /go/bin/kind
(MoeLove) ➜  /go/src/github.com/moelove/iris which kind

# 不帶 @version 進行安裝
(MoeLove) ➜  /go/src/github.com/moelove/iris go install -v sigs.k8s.io/kind
(MoeLove) ➜  /go/src/github.com/moelove/iris which kind
/go/bin/kind
(MoeLove) ➜  /go/src/github.com/moelove/iris kind version
kind v0.9.0 go1.16beta1 linux/amd64

關於 go getgo.mod

go get 將二進位制安裝相關的功能都轉移到了 go install, 僅作為用於編輯 go.mod 檔案的命令存在。在後續版本(計劃是 Go 1.17)中刪掉 go get 安裝二進位制的功能,接下來 go get 的行為就等同於我們現在執行 go get -d 命令了,僅需下載原始碼,並將依賴新增至 go.mod 即可。

go.mod 如何編輯

在 Go 1.16 中,另一個行為變更是 go buildgo test 不會自動編輯 go.mod 了,基於以上資訊,Go 1.16 中將進行如下處理:

  • 通過在程式碼中修改 import 語句,來修改 go.mod

    • go get 可用於新增新模組;
    • go mod tidy 刪除掉無用的模組;
  • 將未匯入的模組寫入 go.mod:

    • go get <package>[@<version>];
    • go mod tidy 也可以;
    • 手動編輯;

從 1.15 升級需要注意什麼?

由於 go buildgo test 不會自動編輯 go.mod 了,所以可以將原本的行為通過 go mod tidy 共同處理。

總結

Go 1.16 中 go installgo get 方面有些不相容的變更,但是 1.16 中模組更加簡潔,減少了使用時的心智負擔,我還是很期待這個版本的。


歡迎訂閱我的文章公眾號【MoeLove】

TheMoeLove

相關文章