Go 包管理工具介绍
golang用过的包管理工具有:
- src
- dep
- vendor
- mod
Go 包管理工具现状
src 是 Go 自带包
src 是 Golang 默认源码目录, 一般 golang 运行时安装后, src 路径就确定了。 src 路径下主要是 Golang 的自带原生包。 不过 src 下的 package 也是可以修改编译的, 但是只能在本地使用。
dep(当前已经弃用)
dep 包管理工具氛围官方的 dep 包管理工具和 godep 这个三方包管理工具。 不过 dep 和 godep 两个包管理工具大体是相同作者开发设计的。 由于当前 dep 包管理工具已经弃用, 不再多做介绍。
vendor 是 Go 内置的依赖管理逻辑
如果当前项目中存在 vendor 目录, 则 Golang 会在vendor 目录中查找依赖,
vendor 文件夹可以分多层, 如下:
.
|-- vendor
| |-- ...
|-- pkg
| |-- a.go
| |-- vendor
| | |-- ...
mod(Go Module) 是当前 Go 最主流的包管理工具, 也是官方的包管理工具
使用 Go Module 来管理依赖, 会在当前 project 项目下生成 go.mod 文件来记录当前项目的依赖模块和版本;
当编译的时候, go mod 会根据指定的依赖生成 go.sum 文件, go.sum 文件是记录每个依赖模块的sha256信息, 防止依赖被非官方篡改。 如果启用了 GOSUMDB 服务器校验的话, Go mod 还会访问 GOSUMDB 的服务器来校验依赖的可信度。
当启用 Go mod 后, 每次项目的依赖都会被放到 $GOPATH/pkg/mod 目录下; $GOPATH/pkg/mod 目录下的包都是带上了版本信息的, 不同版本存放在不同的目录下。
go.mod 由4个关键词组成
- module: 用于指定当前项目的模块名称, 方便其他项目引用
- go: 用于指定当前项目的 Go语言版本
- require: 用于指定当前项目的一个依赖模块和版本
- replace: 用于指定当前项目的一个依赖模块使用指定的替代版本, 也可以指向本地目录
示例
module k8s.io/kubernetes
go 1.18
require (
bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690
github.com/Azure/azure-sdk-for-go v55.0.0+incompatible
...
)
replace (
bazil.org/fuse => bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898
bitbucket.org/bertimus9/systemstat => ../systemstat
...
)
示例分析
- module
module k8s.io/kubernetes
表示当前项目的模块名为 k8s.io/kubernetes;
其他项目引用本项目的时候, 直接在 require 中加上一行 k8s.io/kubernetes 和版本即可。
- go
go 1.18
表示本项目使用的 Golang 版本是 1.18
- require
require (
bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690
github.com/Azure/azure-sdk-for-go v55.0.0+incompatible
)
表示本项目依赖了 bitbucket.org/bertimus9/systemstat 模块, 且依赖的版本是 v0.0.0-20180207000608-0eeff89b0690;
这里的版本 v0.0.0-20180207000608-0eeff89b0690 表示该版本没有tag, 直接使用了指定的commit版本;
其中分为了三段, v0.0.0 表示无tag, 20180207000608 表示commit的时间, 0eeff89b0690 表示该commit的id;
第二个 require 模块的版本 v55.0.0+incompatible 中的 v55.0.0 是该模块的tag, 后缀 +incompatible 表示该模块没有遵循官方推荐的版本命名规则。
官方推荐的版本命名规则如下
一个 Module 的版本号需要遵循 v.. 的格式;
此外,如果 major 版本号大于 1 时,其版本号还需要体现在 Module 名字中。
比如 Module github.com/[orgName]/demo,如果其版本号增长到 v2.x.x 时,其 Module 名字也需要相应的改变为: github.com/[orgName]/demo/v2。
即,如果 major 版本号大于 1 时,需要在 Module 名字中体现版本。
- replace
replace (
bazil.org/fuse => bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898
bitbucket.org/bertimus9/systemstat => ../systemstat
...
)
这段表明项目中的 bazil.org/fuse 依赖替换为 bazil.org/fuse 的 v0.0.0-20160811212531-371fbbdaa898 版本;
bitbucket.org/bertimus9/systemstat 依赖替换为本地 go.mod 同级的 systemstat package。
更具体的细节, 建议自行谷歌, 本文不再繁冗介绍; 后续有时间也可能会单独写一篇 Go mod 的规则介绍。
各依赖管理工具的关系
这个是本文的重点
src vendor mod 三个包管理工具是可以并存的, 在编译的时候, 规则如下:
- 在启用了 go.mod 的前提下会直接在
$GOPATH/pkg/mod查找依赖,$GOPATH不再作为build时的依赖查找对象; - 未启用 go.mod 时:
- 如果当前项目的当前目录存在 vendor, 则优先查找点前vendor下的包;
- 如果当前目录下vendor没有找到, 则继续查找上级目录下的vendor目录;
- 如果到项目根目录的vendor都没有找到依赖包, 则继续查找
$GOPATH/src的包; - 如果
$GOPATH/src没有找到, 则继续查找$GOROOT/src的包。
vendor 的价值:
在有些离线编译的环境, 通过vendor的方式, 可以把依赖全部打入当前项目的vendor目录下; 可以通过如下命令一键将go.mod的依赖导入当前项目的vendor目录:
go mod tidy
go mod vendor
本文正在参加技术专题18期-聊聊Go语言框架