前言
最近在看一些go語言相關的書,發現了一個有意思的事情:其中一本書最新印刷的版本是2017年3月,而golang包管理的後起之秀go module
伴隨go1.11於2018年8月誕生——因此,書裡沒有。
有感於golang發展速度之快,且當下專案中go module
、go vendor
(go1.5之後一個熱門的包管理工具)交織,甚至時不時看到go path
包管理模式在一些文章中死灰復燃,我想有必要正確梳理一下其中的緣由,以便大家選擇合適的包管理模式。
白澤,無腦選擇go module
不好嗎?過時的東西有必要學嗎?
事實上,我認為你可以不用它,但是你得懂為什麼這種技術不推薦甚至被棄用,而且你很難定義什麼是過時的技術,比如我專案中就用到了vendor。很多golang學習者可能有其他語言的基礎,上手go也很快,java有maven,那go必然也有xx包管理工具吧!開啟搜尋引擎輸入go快速入門,安裝與專案構建,有的人查到了go path
,有的人查到了govendor
、有的人則是go module
。
這也是我想寫一篇文章總結的原因(萬一有一天go module也不推薦使用了呢!這種演變的思路值得了解),看過之後保證你能看懂別人文章中寫的GOPATH/src、GOPATH/bin、GOPATH/pkg/mod云云,我們開始。
兩個命令
go install xxx(下載xxx第三方二進位制可執行檔案 )
go get xxx(下載xxx第三方依賴包)
下載可執行檔案/第三方依賴到本地哪裡?不同的包管理工具不同,下面講。
兩個路徑
- GOROOT:go的安裝目錄,類似java的jdk,存放一些內建的開發包和工具。
- GOPATH:go指定的工作空間,用於儲存go專案的程式碼和第三方依賴包。
# mac可以通過go env檢視go相關的環境變數,windows類似
go env
GOROOT="/usr/local/go"
GOPATH="/Users/baize/GolandProjects/"
三個包管理工具
go path【不推薦使用】
go path是最早的依賴包管理方式(Go1.0),啟用GOPATH模式(注意區分GOPATH模式和GOPATH路徑,這是兩個語境),要求將所有工程程式碼要求放在GOPATH/src
目錄下。在工程經過 go build xxx
、go install xxx
或 go get xxx
等指令後,會將拉取的第三方xxx依賴包放在GOPATH/src
目錄下,產生的二進位制可執行檔案放在 GOPATH/bin
目錄下,生成的中間快取檔案會被儲存在 GOPATH/pkg
下。
問題:GOPATH模式下沒有版本控制的概念,在執行 go get
的時候,獲取的永遠是最新的依賴包,下載到GOPATH/src
,如果你有兩個工程依賴一個包的v1和v2版本,則會發生衝突,因為 GOPATH
模式下兩個工程內依賴的匯入路徑都是一樣的,因此兩個工程獲取的都是v2版本。
命令:顯然GOPATH
模式下go get會將程式碼拉取到GOPATH/src
,這個模式已經不推薦使用了。
govendor【不推薦使用】
在 Go 1.5版本之後,Go 提供了 GO15VENDOREXPERIMENT
環境變數(Go 1.6版本預設開啟該環境變數)和 Govendor
包管理工具,用於將 go build
時的應用路徑搜尋調整成為當前工程/vendor
目錄的方式,有效的解決了不同工程使用自己獨立的依賴包目錄。編譯 Go 程式碼會優先從vendor
目錄先尋找依賴包,vendor
目錄如果沒有找到,然後在 GOPATH
中查詢,都沒找到最後在 GOROOT
中查詢。
優勢:因為將第三方依賴完全和工程整合,使得專案構建速度快,且可以工作在無法連線外網的CI/CD流程中。
問題:放棄了依賴重用,使得冗餘度上升
下載:go install github.com/kardianos/govendor(govendor是第三方可執行檔案,下載可執行檔案用go install,用go get也行,但是會有告警)。
命令:govendor --help
檢視所有命令(要先使用go get xxx將xxx依賴下載到$GOPATH/src中,此時go vendor包管理本質是基於GOPATH模式的)
命令 | 功能 |
---|---|
govendor init | 初始化vendor 目錄 |
govendor add | 新增包到vendor 目錄(相關依賴則是從$GOPATH/src中獲取) |
govendor add +external | 新增所有外部包到vendor 目錄 |
govendor get | 拉取依賴包vendor 目錄 |
然後我在govendor的程式碼庫中看到了下面這段話:?(這個README還是兩年前更新的,而且這個庫已經很久不維護了,嗯...)。
go module
從Go1.11開始,官方推出Go module作為包管理工具,且從Go1.13開始為預設選擇啟用。GOMODULE
模式下所有依賴的包存放在GOPATH/pkg/mod
目錄下,所有第三方二進位制可執行檔案放在GOPATH/bin
目錄下,且工程專案可以放在GOPATH
路徑之外,但要求專案中需要有go.mod檔案(該檔案通過go mod init命令初始化可以得到)。
GOMODULE
模式和GOPATH
模式一樣都指定了依賴包存放的位置,而不是如vendor模式放入工程內,區別在於GOMODULE的go.mod
檔案中記錄了所依賴包的具體版本,既實現了工程之間重用依賴包,且解決了GOPATH
模式下不同工程無法依賴同一個包的不同版本的問題。
啟用GOPATH模式要求工程目錄在GOPATH/src
之下,而要使用GO MODULE模式,需要先開啟配置。在Go1.13之後,可以通過如下命令設定GO MODULE啟用狀態。
mac:(windows類似)
# 光開啟也是不行的,需要配合go.mod才能工作,下面講
export GO111MODULE=on
export GO111MODULE=off
# 當專案路徑在 $GOPATH 目錄外部時, 設定為 GO111MODULE = on 當專案路徑位於 GOPATH 內部時,即使存在 go.mod, 設定為 GO111MODULE = off
export GO111MODULE=auto
go mod命令:go help mod檢視相關幫助命令(govendor是第三方可執行檔案,但是go mod命令是go自帶的,不用額外go install)
命令 | 功能 |
---|---|
go mod init | 初始化當前資料夾,建立go.mod 檔案,事實上,如果你的環境中GO111MODULE=on,使用類似goland的工具建立工程會自動生成go.mod |
go mod tidy | 包整理(多的刪去、少的拉取),使用之前自然是import了需要的庫了 |
go mod vendor | 將依賴包複製到工程檔案的vendor 目錄下 |
在GO111MODULE=on
且專案中包含go.mod檔案時,執行go get xxx 或 go install xxx下載的包或者二進位制可執行檔案將放入GOPATH/pkg/mod
目錄和GOPATH/bin
目錄下。
go mod vendor:
這裡著重再提一下go mod vendor,剛剛還說govendor自己都不推薦用了,為什麼GOMODULE
模式還提供了這個關聯go vendor功能的命令呢?
事實上,如果你需要使用vendor模式管理包,說明一定屬於如下兩種情況:
- 工作在
GOPATH
模式下,Go版本早於1.11或者GO111MODULE=off(因為這種方式依賴GOPATH模式,所以已經不推薦了) - 工作在
GO MODULE
模式下,但是還是利用vendor管理依賴包,而go mod vendor就屬於這種情況(算是保留了vendor一線生機,畢竟還是有使用場景的,且go mod vendor利用GOMODULE模式為基礎,摒棄了GOPATH為基礎的govendor)。
結束語
碼字不易,三連才是真情~
剛建了個微信小群,歡迎加入一起嘮嗑,一同備戰秋招!