写在前面
关于 Go Module 的详细资料,可以参考官方的文档。
文章详细地介绍了Go Module的设计以及原理,包含各种命令的使用和 Go 版本的兼容情况。
Go 包管理历史
Go 的包管理大致可以分为3个阶段:GOPATH、vendor、Go Module。
- GOPATH
GOPATH 是 Go 的一个环境变量,程序所依赖的包都放在 GOPATH 下面。一般来讲,GOPATH 默认是用户目录/go,Linux 下是/home/username/go
,Windows 下是C:\Users\username\go
。目录下要有三个文件夹:
bin
:项目编译的二进制文件pkg
:项目编译的中间产物,加速编译src
:项目源码
在工程经过go build
、go install
或go get
等指令后,会将下载的第三方包源代码文件放在$GOPATH/src
目录下, 产生的二进制可执行文件放在 $GOPATH/bin
目录下,生成的中间缓存文件会被保存在 $GOPATH/pkg
下。
这种包管理方式在多个项目依赖不同版本的包时存在显而易见的冲突问题,所以出现了 vendor。
- vendor
vendor 意为供应商,在项目目录下新增一个 vendor 文件夹,项目在查找依赖时,将会优先从 vendor 文件夹下查找依赖。使用 go mod vendor
命令将会创建当前依赖的副本并存储到$ProjectPath/vendor
下。
- Go Module
Go Module 是 Go 11开始支持的包管理方式,如果没有兼容性的考虑,请使用 Go Module 创建项目,而不再使用 Go Path。在 Go Module 的工程下,会存在一个go.mod
文件,这是一个模块的描述文件,声明了当前项目是一个 Go Module,并且声明了名字、版本、依赖等信息。同时还会存在一个go.sum
文件,这是一个用来保存依赖校验和的文件,防止依赖被篡改。
当开启模块支持时,第 1 部分说的 GOPATH 的意义会发生一点变化。
In module-aware mode,
GOPATH
no longer defines the meaning of imports during a build, but it still stores downloaded dependencies (inGOPATH/pkg/mod
; see Module cache) and installed commands (inGOPATH/bin
, unlessGOBIN
is set).
也就是说 GOPATH/pkg/mod
会被当做存放下载的依赖的仓库,称为 Module Cache。如果想要清除 Cache,可以使用go clean -modcache
删除该目录下的所有已下载的依赖。
模块的使用
如何知道当前 Go 采用怎么样的包管理行为呢?我们可以使用go env
命令查看当前的环境变量设置,其中GO11MODULE
变量的值决定了Go的包管理行为。
- If
GO111MODULE=off
, thego
command ignoresgo.mod
files and runs inGOPATH
mode.- If
GO111MODULE=on
or is unset, thego
command runs in module-aware mode, even when nogo.mod
file is present. Not all commands work without ago.mod
file: see Module commands outside a module.- If
GO111MODULE=auto
, thego
command runs in module-aware mode if ago.mod
file is present in the current directory or any parent directory. In Go 1.15 and lower, this was the default behavior.go mod
subcommands andgo install
with a version query run in module-aware mode even if nogo.mod
file is present.
简单来说就是,如果关闭模块支持则继续沿用GOPATH的规则;如果开启模块支持,则一律采用Go Module的支持;如果设置为自动,则取决于当前项目根路径下是否存在go.mod
文件。
开启
vendor
时,go build
、go test
等命令将只考虑vendor
目录下的包,而不再从网络或者module cache
下找包。但是
go get
、go mod download
、go mod tidy
等不受影响,还是会下载包到module cache
。
常用命令
go mod init
: 用来初始化模块go mod tidy
: 添加依赖并移除不需要的依赖项go get
: 获取依赖,如果不存在将从网络下载,同时更新go.mod
的依赖项
使用go get package@version,可以获取指定版本的包。
除了具体的版本,也可以是@master、@latest、@git-tag。
特别的是,使用@none可以移除包依赖。
# Remove a dependency on a module and downgrade modules that require it
# to versions that don't require it.
$ go get golang.org/x/text@none
go get 与 go install
go get
会下载依赖,同时更新go.mod文件。- 而
go install
则是下载、编译、安装依赖(如果存在Execuables
、Programs
、Commands
也就是main package
,则会安装到GOBIN
下,否则只是下载到module cache
),不会修改go.mod
文件。
原本
go get
也会编译安装,如果加入-d
参数,则不会进行编译安装。而
-d
参数在 Go 1.17已经过时,自从 Go 1.18 后,总是默认启用。官方建议使用
go get
进行依赖的管理,而使用go install
进行可执行文件的安装。