【轉】go.mod 文件中的indirect準確含義

 

原文:https://my.oschina.net/renhc/blog/3162751

-------------------------

 

在使用 Go module 過程中,隨着引入的依賴增多,也許你會發現go.mod文件中部分依賴包後面會出現一個// indirect的標識。這個標識總是出現在require指令中,其中// 與代碼的行註釋一樣表示註釋的開始,indirect表示間接的依賴。

比如開源軟件 Kubernetes(v1.17.0版本)的 go.mod 文件中就有數十個依賴包被標記爲indirect

require (
	github.com/Rican7/retry v0.1.0 // indirect
	github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7 // indirect
	github.com/boltdb/bolt v1.3.1 // indirect
	github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b // indirect
	github.com/codegangsta/negroni v1.0.0 // indirect
	...
)

在執行命令go mod tidy時,Go module 會自動整理go.mod 文件,如果有必要會在部分依賴包的後面增加// indirect註釋。一般而言,被添加註釋的包肯定是間接依賴的包,而沒有添加// indirect註釋的包則是直接依賴的包,即明確的出現在某個import語句中。

然而,這裏需要着重強調的是:並不是所有的間接依賴都會出現在 go.mod文件中。

間接依賴出現在go.mod文件的情況,可能符合下面所列場景的一種或多種:

  • 直接依賴未啓用 Go module
  • 直接依賴go.mod 文件中缺失部分依賴

直接依賴未啓用 Go module

如下圖所示,Module A 依賴 B,但是 B 還未切換成 Module,也即沒有go.mod文件,此時,當使用go mod tidy命令更新A的go.mod文件時,B的兩個依賴B1和B2將會被添加到A的go.mod文件中(前提是A之前沒有依賴B1和B2),並且B1 和B2還會被添加// indirect的註釋。

此時Module A的go.mod文件中require部分將會變成:

require (
	B vx.x.x
	B1 vx.x.x // indirect
	B2 vx.x.x // indirect
)

依賴B及B的依賴B1和B2都會出現在go.mod文件中。

直接依賴 go.mod 文件不完整

如上面所述,如果依賴B沒有go.mod文件,則Module A 將會把B的所有依賴記錄到A 的go.mod文件中。即便B擁有go.mod,如果go.mod文件不完整的話,Module A依然會記錄部分B的依賴到go.mod文件中。

如下圖所示,Module B雖然提供了go.mod文件中,但go.mod文件中只添加了依賴B1,那麼此時A在引用B時,則會在A的go.mod文件中添加B2作爲間接依賴,B1則不會出現在A的go.mod文件中。

此時Module A的go.mod文件中require部分將會變成:

require (
	B vx.x.x
	B2 vx.x.x // indirect
)

由於B1已經包含進B的go.mod文件中,A的go.mod文件則不必再記錄,只會記錄缺失的B2。

總結

爲什麼要記錄間接依賴

在上面的例子中,如果某個依賴B 沒有go.mod文件,在A 的go.mod文件中已經記錄了依賴B及其版本號,爲什麼還要增加間接依賴呢?

我們知道Go module需要精確地記錄軟件的依賴情況,雖然此處記錄了依賴B的版本號,但B的依賴情況沒有記錄下來,所以如果B的go.mod文件缺失了(或沒有)這個信息,則需要在A的go.mod文件中記錄下來。此時間接依賴的版本號將會跟據Go module的版本選擇機制確定一個最優版本。

如何處理間接依賴

綜上所述間接依賴出現在go.mod中,可以一定程度上說明依賴有瑕疵,要麼是其不支持Go module,要麼是其go.mod文件不完整。

由於Go 語言從v1.11版本才推出module的特性,衆多開源軟件遷移到go module還需要一段時間,在過渡期必然會出現間接依賴,但隨着時間的推進,在go.mod中出現// indirect的機率會越來越低。

出現間接依賴可能意味着你在使用過時的軟件,如果有精力的話還是推薦儘快消除間接依賴。可以通過使用依賴的新版本或者替換依賴的方式消除間接依賴。

如何查找間接依賴來源

Go module提供了go mod why 命令來解釋爲什麼會依賴某個軟件包,若要查看go.mod中某個間接依賴是被哪個依賴引入的,可以使用命令go mod why -m <pkg>來查看。

比如,我們有如下的go.mod文件片斷:

require (
	github.com/Rican7/retry v0.1.0 // indirect
	github.com/google/uuid v1.0.0
	github.com/renhongcai/indirect v1.0.0
	github.com/spf13/pflag v1.0.5 // indirect
	golang.org/x/text v0.3.2
)

我們希望確定間接依賴github.com/Rican7/retry v0.1.0 // indirect是被哪個依賴引入的,則可以使用命令go mod why來查看:

[root@ecs-d8b6 gomodule]# go mod why -m github.com/Rican7/retry
# github.com/Rican7/retry
github.com/renhongcai/gomodule
github.com/renhongcai/indirect
github.com/Rican7/retry

上面的打印信息中# github.com/Rican7/retry 表示當前正在分析的依賴,後面幾行則表示依賴鏈。github.com/renhongcai/gomodule 依賴github.com/renhongcai/indirect,而github.com/renhongcai/indirect依賴github.com/Rican7/retry。由此我們就可以判斷出間接依賴github.com/Rican7/retry是被github.com/renhongcai/indirect引入的。

另外,命令go mod why -m all則可以分析所有依賴的依賴鏈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章