淺談GoPath和Go Modules包管理

 

目錄
  • 一、概述
  • 二、GOPATH介紹
    • 2.1 GOPATH目錄
    • 2.2 GOPATH的缺點
  • 三、GO Module介紹
    • 3.1 設定GO111MODULE環境變量
    • 3.2 初始化mod
    • 3.3 go mod命令
  • 四、總結

 

一、概述

大多數語言都有「依賴」、「包」等概念,Go語言的依賴處理經歷了幾回變革git

最先的時候,Go所依賴的全部的第三方庫都放在GOPATH這個目錄下面github

從v1.5開始開始引入vendor模式,若是項目目錄下有vendor目錄,那麼go工具鏈會優先使用vendor內的包進行編譯、測試等編程

從v1.11開始,引入了Go Module 做爲依賴解決方案,到v1.14宣佈Go Module已經能夠用於生產環境,到v1.16版本開始Go Module默認開啓json

二、GOPATH介紹

2.1 GOPATH目錄

GOPATH是什麼,輸入以下命令查看網絡

# go env GOPATH
GOPATH="/Users/ssgeek/go"

進入到該目錄下,目錄結構以下ide

# cd `go env GOPATH`
# tree -L 2 .
.
├── bin
│   ├── dlv
│   ├── go-outline
│   ├── gomodifytags
│   ├── gopkgs
│   ├── goplay
│   ├── gopls
│   ├── gotests
│   ├── impl
│   └── staticcheck
├── pkg
│   ├── mod
│   └── sumdb
└── src
    └── github.com
    ...

三個目錄中存放的文件說明以下工具

bin //用來存放編譯後的可執行文件
pkg //用於存放編譯後生成的歸檔文件
src //用來存放go源碼文件

2.2 GOPATH的缺點

在使用GOPATH的模式下,咱們須要將應用代碼存放在固定的$GOPATH/src目錄下,而且若是執行go get來拉取外部依賴會自動下載並安裝到$GOPATH目錄下測試

第三方套件只要不是官方庫,都須要放置在GOPATH/src的路徑下才可使用ui

go get最經常使用在當咱們想用別人公開在GitHub上的套件,能夠幫咱們從網絡clone到GOPATH/src裏面。雖然這樣很方便,可是會發現GOPATH/src下會很複雜,除了有你本身開發的代碼目錄,同時也包含其餘第三方庫的專屬目錄加密

咱們給不一樣的項目設置不一樣的GoPath,優勢很是明顯:

便於管理項目,每一個項目都是不一樣的GoPath,這對於咱們管理多個Golang項目而言,可以很是清晰的處理項目結構。若是咱們把全部項目都放在同一個GoPath的src包下,那麼項目的結構就會變得很是混亂,難以管理

可是當咱們須要依賴第三方的包的時候,不一樣的項目設置不一樣的GoPath的缺點也很是明顯:

  1. 第三方依賴的包和咱們本身的Golang包混在一塊兒,會給咱們的項目文件管理帶來必定的麻煩
  2. 不一樣的GoPath都須要下載依賴,那麼磁盤中重複的依賴就會很是多,會佔用咱們大量的磁盤空間

三、GO Module介紹

爲了解決GOPATH的問題,所以官方在1.11開始推出了Go Modules的功能。Go Modules解決方式很像是Java看到Maven的作法,將第三方庫儲存在本地的空間,而且給項目代碼去引用

3.1 設定GO111MODULE環境變量

總共能夠設置三種不一樣的值

  • auto

默認值,go命令會根據當前目錄來決定是否啓用modules功能。須要知足兩種情形:
該目錄不在GOPATH/src/下
當前或上一層目錄存在go.mod文件

  • on

go命令會使用modules,而不會去GOPATH目錄下查找。

  • off

go命令將不會支持module功能,尋找依賴按照之前GOPATH的作法去尋找

目前1.16版本默認將這個參數設置成on,並且可能以後的版本會棄用掉GO111MODULE,所以建議要開發Go項目時就再也不使用GOPATH了,而是採用Go Modules的作法,所以建議都設定爲on

採用Go Modules,下載下來的第三方依賴就位於GOPATH/pkg/mod目錄下

3.2 初始化mod

go mod init <module name>

<module name>可填可不填,不填的話預設就是默認的文件名稱go.mod

在此文件中能夠寫如下幾個關鍵字:

  • module

定義模組路徑

  • go

定義go語言version

  • require

指定依賴,預設是最新版,能夠指定版本號

  • exclude

排除該依賴和其版本

  • replace

使用不一樣的依賴版本並替換原有的依賴版本註解
indirect表明被間接導入的依賴包

假設如今我要引入GitHub上的gin-gonic/gin的依賴,以下定義:

module myProject
go 1.16
require github.com/gin-gonic/gin v1.6.3

再執行如下指令:

go mod xxx

會將須要的依賴安裝在GOPATH/pkg/mod目錄裏面

gin@v1.4.0 gin@v1.6.3 gin@v1.7.1

除了go.mod以外,go命令還維護一個名爲go.sum的文件,其中包含特定模塊版本內容的預期加密哈希
go命令使用go.sum文件確保這些模塊的將來下載檢索與第一次下載相同,以確保項目所依賴的模塊不會出現意外更改,不管是出於惡意、意外仍是其餘緣由。 go.mod和go.sum都應檢入版本控制。
go.sum不須要手工維護,因此能夠不用太關注

只要有開啓go modules功能,go get 就不會像之前同樣在GOPATH/src下放置依賴,而是會放在GOPATH/pkg/mod裏面,而且go.mod會寫好引入

3.3 go mod命令

經常使用

go mod init:初始化go mod, 生成go.mod文件,後可接參數指定 module 名,上面已經演示過。
go mod download:手動觸發下載依賴包到本地cache(默認爲$GOPATH/pkg/mod目錄)
go list -m -json all:以 json 的方式打印依賴詳情

其餘

go mod graph: 打印項目的模塊依賴結構
go mod tidy :添加缺乏的包,且刪除無用的包
go mod verify :校驗模塊是否被篡改過
go mod why: 查看爲何須要依賴
go mod vendor :導出項目全部依賴到vendor下
go mod edit :編輯go.mod文件

四、總結

GoPath所引出的問題,就是由於第三方類庫的包所致使的,因此在有了GoModule以後,GoPath和GoModule就分別負責不一樣的職責,共同爲Golang項目服務

GoPath用來存放咱們從網上拉取的第三方依賴包
GoModule用來存放咱們本身的Golang項目文件,當本身的項目須要依賴第三方的包的時候,咱們經過GoModule目錄下的一個go.mod文件來引用GoPath目錄pkg包下的mod文件夾下的第三方依賴便可

這樣以來,既解決了原來只能侷限在GoPath目錄src包下進行編程的問題,也解決了第三方依賴包難以管理和重複依賴佔用磁盤空間的問題

相關文章
相關標籤/搜索