依赖管理(go mod)
目录
一、GOPATH
二、Vendor
三、Go Module
Go的依赖管理主要经过了3个重要阶段
1、GOPATH
2、Vendor
3、Go Module
早期Go使用GOPATH进行依赖管理,但是GOPATH不方便管理多个版本。
后来增加了Vendor,允许把项目连同代码一起管理。
18年,Go1.11引入全新的依赖管理工具Go Module,直到Go1.14才走向成熟。
从GOPATH到vendor,再到Go Module,这是一个不断演进的过程,了解每代依赖管理的痛点,能够更好的明白下一代依赖管理的初衷。
故,我将会从GOPATH讲起,经过vendor最后到Go Module。
各版本依赖管理的时间分布
依赖管理方法 | 引入版本 | 时间 | 状态 |
GOPATH | Go 1.0 | 2012 年(Go 1.0) | Go 的早期依赖管理方式,已逐步被 Go Module 取代,但仍在支持 |
Vendor | Go 1.5 | 2015 年 | 一种解决 GOPATH 依赖冲突的过渡方案,Go 1.6 起成为默认方案,但现在被 Go Module 取代 |
Go Module | Go 1.11 | 2018 年(实验) | Go 1.13 起成为默认依赖管理方式,是目前官方推荐的管理方案 |
一、GOPATH
刚刚接触GO的新手,一般都对GOPATH感到困惑。通常由两方面造成的
Go语言解决办法有两种:
- 将从前的卸了,再亲自安装一次
- 听我下面的讲解 Ψ( ̄∀ ̄)Ψ
建议选择第二种方法,既然来到了这里,就要相信我的讲解。本部分主要介绍GOPATH及与其密切相关的GOROOT,首先看一下GOROOT。
1. GOROOT是什么
定义:
通常,我们说安装Go语言,实际上是安装Go的编译器与标准库,两者位于同一个安装包中。
假如在Windows上,使用Installer安装Go,他们会被默认安装到C:\Go目录下。该目录即为GOROOT目录。
里面包含了开发Go应用程序所需要的所有组件。如编译器、标准库和工具所在的位置。
它是 Go 语言自带的环境变量,用户通常无需更改。
作用:
- Go 编译器及工具链所在的目录。
- Go 的标准库代码(如 fmt、os 等)。
默认值:
安装 Go 语言时,GOROOT 会自动配置为安装目录的路径。例如:
- Windows 上:C:\Go
- macOS/Linux 上:/usr/local/go
是否需要手动设置:
一般不需要手动设置 GOROOT,Go 安装程序会自动配置。如果需要自定义(比如安装多个 Go 版本),可以手动设置环境变量 GOROOT。
查看当前的 GOROOT:
go env GOROOT // 查看路径
2. GOPATH:工作区目录
定义:
GOPATH 是 Go 工作区目录,用于存放:
- 代码:所有项目的源码(src)。
- 依赖包:第三方库的下载路径(pkg)。
- 可执行文件:编译后的二进制文件(bin)。
作用:
- Go 工具链在哪里查找和存储你的 Go 项目和依赖。
- go install 和 go build 命令,生成可执行文件或中间文件。
默认值:
如果没有显式设置,Go 会将 GOPATH 默认设置为用户主目录下的 go 文件夹:
- Windows 上:%USERPROFILE%\go
- macOS/Linux 上:$HOME/go
目录结构:
一个典型的 GOPATH 目录结构如下:
GOPATH/├── bin/ # 存放可执行文件├── pkg/ # 存放已编译的依赖包└── src/ # 存放 Go 项目的源码
如何设置 GOPATH:
你可以手动设置 GOPATH 为自定义的目录(可多路径,但较少用)。例如:
# Linux/macOSexport GOPATH=/path/to/your/workspace# Windows(通过系统环境变量设置)set GOPATH=C:\path\to\your\workspace
查看当前的 GOPATH:
go env GOPATH
缺点:
GOPATH的优点是简单,但是不能很好的适应实际项目的工程需求。比如有两个项目A和B,如果两个项目都引用第三方库T,只是版本不同。
- 使用,T v1.0
- 使用,T v2.0
由于编译器固定依赖GOPATH / src 下查找GOPATH / src / T 这条路径,又因为无法在同一个GOPATH目录下储存T的两个版本。所以A、B无法共享同一个GOPATH,需要各自维护一个,带来极大的不便。针对GOPATH的缺点,Go语言社区提供了Vendor机制。从此依赖管理进入了第二阶段。
GOROOT 与 GOPATH 的主要区别
区别 | GOROOT | GOPATH |
定义 | Go 安装目录 | Go 工作区,存放用户项目和依赖 |
包含内容 | 标准库、编译器、工具等 | 用户源码、依赖包缓存、可执行文件等 |
是否可修改 | 一般不需要修改,由 Go 自动设置 | 用户可以设置为任意路径 |
使用场景 | Go 标准库查找、工具链使用 | 非模块化项目存储、编译生成文件 |
总结
- 指向 Go 安装目录,包含标准库和工具,不建议修改。
- 指向工作区目录,存放用户项目和依赖,是用户项目的主要工作目录。
二、Vendor
上部分,我们介绍了使用GOPATH的痛点:多个项目无法共享同一个GOPATH,虽然vendor仍然无法多个项目无法共享同一个GOPATH,但是它提供了一种机制,让项目的依赖隔离而不互相干扰。
自 Go 1.6起,vendor机制正式启用,它允许把项目存放在vendor的目录中,可以把这个vendor目录,简单的理解成私有的GOPATH目录。项目编译时,编译器会优先从vendor目录中寻找依赖包,如果在vendor中找不到,才会去GOPATH中寻找。
虽然vendor并未推出历史舞台,甚至在离线场合下更适用。
但是Go Module已成为主流,如果读者们想得到vendor更详细的资料,可以上网另行查询。
三、Go Module
在Go 1.11中,Module的特性首次被引用,标志着Go的依赖进入第三个时代。
Go Module 基本上解决了 GOPATH 和 vendor 时代的遗留问题,看到这里的读者基本能了解:
GOPATH 时代,最大的困惑时无法让多个项目共享package的不同版本。
在vendor时代,可以通过将每个项目依赖的 package 放到 vendor 中可以解决,但是使用 vendor的问题是无法很好的管理依赖package,比如升级package。
而Go Module 更像一种全新的依赖管理方案。
Go Module基础
1、module的定义
官方给 module 的定义是:A module is a collection of related Go packages that are versioned together as a single unit.
定义非常清晰,一组 package 的集合一起被标记版本,即一个 module。
通常而言,一个仓库包含一个 module(虽然也可以包含多个,但不推荐),所以仓库、module 和 package 的关系如下:
◎ 一个仓库包含一个或多个 module。
◎ 你每个module 包含一个或多个 package。
◎ 每个 package 包含一个或多个源文件。
另外,一个 module 的版本号规则必须遵循语义化规范,版本号必须使用v(major).(minor).(patch)格式,比如v0.1.0、v1.2.3等。
下方给出了,语义化版本的规范。
语义化版本的规范
语义化版本 (Semantic Versioning) 已成为事实上的标准,几乎知名的开源项目都遵循该规范,更详细的信息请前往 semver官网査看,在此只提炼一些要点,以便于后续的阅读。
版本格式 v(major).(minorr).(patch)中的 major 指的是大版本,minor 指的是小版本,patch 指的是补丁版本。
◎ major: 当发生不兼容的改动时才可以增加该版本,比如 v2.x.y与 v1.x.y是不兼容的。
◎ minor: 当有新增特性时才可以增加该版本,比如 v1.17.0 是在 v1.16.0的基础上增加了新的特性,同时兼容 v1.16.0。
◎ patch: 当有 Bug修复时才可以增加该版本,比如 v1.17.1修复了 v1.17.0 上的 Bug,没有增加新特性。
语义化版本规范的好处是,用户通过版本号就能了解版本信息。
2、快速实战
纸上得来终觉浅,觉知此事要躬行,后续我会在补充一下实战,让大家对Go Module认识的更加清楚。
讲到这里了,大家肯定对 go mod 与 Go Module 之间的差异有些许疑惑,接下来我来细细讲解。
Go Module 与 go mod 的区别
区别 | Go module | go mod 命令 |
定义 | Go 的模块化系统,用于管理依赖和版本 | Go 工具链中的子命令,用于操作和管理 Go module |
作用 | 使得 Go 项目支持依赖版本管理、减少冲突 | 具体操作模块的工具,包含初始化、下载、清理等子命令 |
使用方式 | 自动在项目根目录生成 go.mod 文件,记录模块的依赖信息 | 使用如 go mod init 等命令管理模块依赖 |
依赖管理 | 管理项目的依赖关系和版本控制 | 提供修改 go.mod 文件的命令,以方便操作模块 |
举例
在项目的根目录下:
# 初始化一个 Go module,会在当前目录生成 go.mod 文件go mod init my_project# 整理依赖,自动移除未使用的依赖包go mod tidy# 下载所有依赖go mod download
总体来说:
- module 是 的模块化系统的概念,它定义了依赖管理的机制。
- mod 是管理 Go module 的命令集合,用于具体执行对模块的各种操作。
3、go.mod 与 指令
在 Go 中,go.mod 文件和 go mod 命令行工具提供了依赖管理的核心功能。以下是详细说明。
1. go.mod 文件
go.mod 是 Go 项目的模块文件,用于定义模块名、依赖项和版本等信息。一个典型的 go.mod 文件示例如下:
module example.com/myappgo 1.20require (github.com/gin-gonic/gin v1.8.1golang.org/x/crypto v0.5.0
)replace golang.org/x/crypto v0.5.0 => ./local/crypto
- module:定义当前项目的模块路径,一般为代码仓库路径。
- go:指定所使用的 Go 版本(这里是 1.20)。
- require:列出当前模块所依赖的其他模块及其版本。
- replace:用于指定模块的替代版本或本地替代路径,通常在开发调试阶段使用。
go.mod 文件自动生成
可以通过在项目目录运行 go mod init <module_name> 来自动生成 go.mod 文件。例如,go mod init example.com/myapp。
2. go mod 命令行管理
go mod 命令行工具用于管理模块的依赖项和版本控制,以下是常用的命令:
2.1 go mod init <module_name>
初始化当前项目的模块系统,生成 go.mod 文件:
go mod init example.com/myapp
2.2 go mod tidy
清理依赖,移除不再使用的包并添加遗漏的包。
go mod tidy
- go mod tidy 会检查 go.mod 和 go.sum 文件,移除未引用的模块,并确保所有依赖项存在于 go.sum 文件中。
2.3 go mod download
下载依赖包到本地的模块缓存中,但不会修改 go.mod 文件。
go mod download
2.4 go mod vendor
将所有依赖的包下载到项目的 vendor 目录中。
go mod vendor
- Go 1.14 引入的 vendor 模式在构建项目时优先从 vendor 目录中查找依赖项,可以用来解决部署环境中网络不通畅的问题。
2.5 go mod graph
展示依赖模块之间的关系图,帮助理解依赖结构。
go mod graph
2.6 go mod verify
验证依赖的包文件是否正确,检查 go.sum 文件中保存的哈希值是否匹配下载的模块。
go mod verify
讲到这里也接近了尾声,创作本篇博客倾尽了全力,虽不免仍有些片面。但从基础上看,带领大家,重新认识了一遍依赖管理,并从GOPATH讲起,经过vendor最后到Go Module,还是不错的。
希望大家有收获,期待下次再见。