Go Wiki: GOPATH

GOPATH 變數

使用標準庫之外的依賴項進行 Go 開發是使用 Go 模組完成的。使用 Go 模組時,GOPATH 變數(在 Unix 上預設為 $HOME/go,在 Windows 上預設為 %USERPROFILE%\go)用於以下目的:

  • go install 命令將二進位制檔案安裝到 $GOBIN,預設為 $GOPATH/bin
  • go get 命令將下載的模組快取到 $GOMODCACHE,預設為 $GOPATH/pkg/mod
  • go get 命令將下載的校驗和資料庫狀態快取到 $GOPATH/pkg/sumdb

有關 GOPATH 變數的完整詳細資訊,請參閱 go 命令文件。本頁其餘部分涉及 GOPATH 開發模式,該模式現已棄用。

GOPATH 開發模式

在 Go 模組之前,使用依賴項進行 Go 開發使用“GOPATH 開發模式”,簡稱“GOPATH 模式”。在 GOPATH 模式下,go 命令將 GOPATH 變數用於以下目的:

  • go install 命令將二進位制檔案安裝到 $GOBIN,預設為 $GOPATH/bin
  • go install 命令將 import "example.com/y/z" 的編譯包檔案安裝到 $GOPATH/pkg/example.com/y/z.a
  • go get 命令將滿足 import "example.com/y/z" 的原始碼下載到 $GOPATH/src/example.com/y/z

棄用並移除 GOPATH 開發模式

Go 模組是 GOPATH 開發模式的替代品,旨在將包版本概念引入整個 Go 生態系統。

從 GOPATH 開發模式到 Go 模組的過渡是漸進的,跨越了許多 Go 版本:

  • Go 1.11 (2018 年 8 月) 引入了 GO111MODULE 變數,預設為 auto。當 GO111MODULE=off 時,go 命令始終使用 GOPATH 模式。當 GO111MODULE=on 時,go 命令始終使用模組模式。當 GO111MODULE=auto(或未設定 GO111MODULE)時,go 命令根據當前目錄決定模式。如果當前目錄位於 $GOPATH/src 之外,並且位於其根目錄中包含 go.mod 檔案的原始碼樹中,則 go 命令使用 Go 模組模式。否則,go 命令使用 GOPATH 模式。此規則確保在 auto 模式下,在 $GOPATH/src 中執行的所有命令都不受影響,但允許使用者在其他目錄中試驗模組。

  • Go 1.13 (2019 年 8 月) 調整了 GO111MODULE=auto 模式,移除了 $GOPATH/src 限制:如果 $GOPATH/src 內的目錄具有 go.mod 檔案,則在該目錄或其子目錄中執行的命令現在使用模組模式。這允許使用者繼續以基於匯入的層次結構組織其簽出程式碼,但為單個簽出使用模組。

  • Go 1.16 (2021 年 2 月) 將預設值更改為 GO111MODULE=on,始終使用模組模式。也就是說,GOPATH 模式將預設完全停用。需要為下一個版本使用 GOPATH 模式的使用者可以明確設定 GO111MODULE=autoGO111MODULE=off

  • Go 1.NN (???) 將完全移除 GO111MODULE 設定和 GOPATH 模式,始終使用模組模式。

請注意,移除 GOPATH 開發模式並意味著移除 GOPATH 變數。它仍將用於本頁頂部列出的目的。

常見問題

GOPATH 變數會被移除嗎?

不會。GOPATH 變數(在環境中或透過 go env -w 設定)不會被移除。它仍將用於確定預設的二進位制檔案安裝位置、模組快取位置和校驗和資料庫快取位置,如本頁頂部所述。

我還能在 GOPATH/src/import/path 中編寫程式碼嗎?

是的。許多 Go 開發者欣賞這種約定提供的結構,並將其模組倉庫簽入其中。您的所有程式碼只需要一個 go.mod 檔案即可開始使用模組。請參閱 go mod init

如何在 GOPATH/src 中的一個倉庫中編譯另一個倉庫中進行的更改?

如果您想在構建另一個模組時使用一個模組中未釋出的更改,您可以在另一個模組的 go.mod 中新增一個 replace 行。

例如,如果您已將 golang.org/x/websitegolang.org/x/tools 簽出到 $GOPATH/src/golang.org/x/website$GOPATH/src/golang.org/x/tools,那麼為了使您的 website 本地構建自動使用 tools 中的更改,您需要在 $GOPATH/src/golang.org/x/website/go.mod 中新增以下內容:

replace golang.org/x/tools => ../tools

當然,replace 指令對 $GOPATH 一無所知。如果您將這兩個專案簽出到 $HOME/mycode/website$HOME/mycode/tools,同樣的行也會正常工作。

GOPATH 開發模式為何被移除?

GOPATH 開發模式的核心是自動提供所有這些 replace 行,以便您為依賴項構建的程式碼就是您恰好在計算機上籤出的程式碼。這意味著您的構建會受到您可能忘記的舊簽出的影響。這意味著您在一臺機器上獲得的構建可能與另一臺機器上的不同,即使從相同頂級倉庫的相同版本開始也是如此。這意味著您獲得的構建可能與同一專案中的另一個開發者獲得的構建不同。Go 模組解決了所有這些可重現性問題。所有這些問題的根本原因是 GOPATH 模式沒有任何包版本的概念。

除了可重現性之外,Go 模組還提供了一種清晰的方式來處理代理和安全下載。當您 git clone 一個專案並獲取其依賴項時,這些依賴項會經過加密檢查(使用 go.sum 檔案),以確保它們與原始開發者使用的位相同。唯一受信任的部分是頂級 git clone。同樣,這隻有在 Go 模組(與 GOPATH 模式相反)具有包版本概念的情況下才可能實現。

對於 Go 本身的未來演進,模組清楚地標記了特定檔案樹是用哪個版本的 Go 語言編寫的。這使得在 Go 的後續版本中可以停用有問題的功能——例如,string(1),許多人認為它會產生 "1",但實際上會產生 "\x01" (Ctrl-A)——同時保持舊程式能夠構建(因為它們明確標記為為舊版本 Go 編寫)。

還有更多類似的例子。

所有這些在目前的 GOPATH 開發模式下都不可能實現。我們無法在不淘汰 GOPATH 模式的情況下推動生態系統向前發展並真正依賴 Go 模組的這些重要特性。

(您可能還會問:為什麼不直接將這些東西新增到 GOPATH 模式?答案是:我們已經這樣做了,結果就是 Go 模組。)

何時決定棄用 GOPATH 開發模式?

最初的計劃是在 Go 1.13 中棄用 GOPATH 模式,但我們想花更多時間使模組對儘可能多的 Go 使用者更加健壯,因此棄用被推遲到那個版本之後。對 問題 #41330 和 golang-tools 組的討論沒有發現任何剩餘的阻礙 GOPATH 棄用的問題,因此現在計劃在 Go 1.16 中棄用,並在未來的版本中移除,如上面的時間線所述。

如果我對從 GOPATH 開發模式遷移到 Go 模組有更多疑問,該怎麼辦?

請參閱 golang.org/help 獲取資源列表。如果這些都不合適,請隨時在此處提交問題。我們希望每個人都能成功採用 Go 模組。


此內容是 Go Wiki 的一部分。