Go 依赖管理演进
Go 语言中,依赖管理的演进分为三个阶段,依次是:
- GOPATH
- Go Vendor
- Go Module
GOPATH
配置环境变量 $GOPATH
,GOPATH 下有以下三个文件夹:
- bin:项目编译的二进制文件
- pkg:项目编译的中间产物,用于加速编译
- src:项目源码
项目的代码直接依赖于 src 下的代码,可以通过 go get
命令将依赖包下载到 src 下。
GOPATH 的缺点在于:无法实现对 package 的多版本控制。
若 A 和 B 依赖于某一 package 的不同版本,这样的情况 GOPATH 无法解决。
Go Vendor
项目目录下增加 vendor 文件夹,所有依赖包的副本存放在项目下的 vendor 文件夹中。
若 vendor 中没有依赖包,则会在 GOPATH 下去寻找。
Go Vendor 的缺点在于:无法控制依赖的版本、更新项目可能出现依赖冲突。
若一个项目依赖于 package B 和 packag C,而 package B 依赖于 package D-V1 版本;package C 依赖于 package D-V2 版本。这样的场景下,Go Vendor 无法很好的解决。
Go Module
Go Module 通过 go.mod 文件管理依赖包版本。
通过 go get / go mod 工具,管理依赖包。
Go Module 详解
依赖管理三要素
Go Module 中,依赖管理需要三要素:
- go.mod:配置文件,描述依赖。
- Proxy:中心仓库管理依赖库。
- go get/mod:本地工具。
go.mod
go.mod 文件主要由三部分构成:
- 依赖管理基本单元:标识了这个模块可以在哪里找到(被其他人引用)。
- 原生库:Go 的版本号。
- 单元依赖:描述依赖关系,主要两部分组成。
- 包名(Module Path)
- 版本号
其中,可以看到单元依赖的一些配置:
- version:
- 语义化版本:
${MAJOR}.${MINOR}.${PATCH}
,MAJOR 是一个大版本,不同 MAJOR 可以不兼容。MINOR 做出了一些新增函数,同一个 MAJOR 下需要相互兼容。PATCH 做了一些 bug 修复。 - 基于 commit 伪版本:
vx.0.0-yyyymmddhhmmss-abcdefgh1234
。
- 语义化版本:
- indirect:对于没有直接依赖的 package,就用 indirect 标识出来。
- incompatible:如果 MAJOR 版本大于 1 时,其版本号还需要体现在 Module 名字中(如
xxx/xx/v2
)。但是如果 Module 名字未遵循这条规则,则会打上 incompatible 标记。
Go 在选择版本时,会选择最低的兼容版本:
如下图中,最终编译时所使用的 C 项目版本为 1.4 版本。
Proxy
Go Proxy 是一个服务站点,他会缓存源站中的软件内容,缓存的软件版本不会改变,源站软件删除后依然可用。
GOPROXY="https://proxy1.cn,https://proxy2.cn,direct"
,含义是依次从 proxy1、proxy2、源站中获取 package。
go get/mod
go get:
go get example.org/pkg
,参数如下:@update
:默认,获取最新版本。@none
:删除依赖。@v1.1.1
:语义化版本。@45dfsf
:特定的 commit。@master
:分支的最新 commit。
go mod:参数如下:
init
:初始化,创建 go.mod 文件。download
:下载模块到本地。tidy
:增加需要的依赖,删除不需要的依赖。