go mod详解

一、go mod 是什么

go mod 是 go 1.11 引入的依赖管理工具,之前的 go 中有 package 的概念,go mod 则引入了 module 的概念。 比如在 engine/mai 目录下运行命令 go mod init silverbolt/mai,在 mai 目录下会生成一个 go.mod 文件, 文件第一行 module silverbolt/mai 就是说当前目录是一个名为 silverbolt/mai 的 module。

二、go mod 要解决什么问题

  1. go mod 可以用来管理 vendor 目录,替换 govendor 这个工具。

  2. 使用 go mod,可以在把 go 项目放在任意位置,而不再必须放在 GOPATH 中。

三、go mod 使用

3.1 在项目中使用

  1. 进入在任意位置的 go 项目,运行 go mod init [module_name] 命令生成 go.mod

  2. 运行 go mod tidy 命令添加缺失的 module,移除不再使用的 module

  3. 运行 go mod download 命令下载依赖 module 到本地 cache

  4. (可选)运行 go mod vendor 命令将依赖拷贝一份到当前 module 的 vendor 目录

注:使用 go module 之后,项目目录下的 vendor 目录可以要也可以不要。 go mod 的 cache 位于 $GOPATH/pkg/mod,没有 vendor 目录编译的时候会使用 cache 下面的依赖。

3.2 添加本地依赖

向 go.mod 中添加本地依赖:

require silverbolt/chin v0.0.0

replace silverbolt/chin v0.0.0 => ../chin

上面中的版本号不能省略,但可以随便写。

四、go mod 的问题

4.1 环境变量 GO111MODULE

使用 go mod 需要将 GO111MODULE 环境变量设为 on 或者 auto。 在 1.11 和 1.12 版本的 go 中,需要 export GO111MODULE=on, 在 1.13 版本的 go 中,GO111MODULE 被默认置为 auto。

GO111MODULE 为 on 和 off 可以理解为两种不同的模式,两种模式下,一些 go 的命令会有区别。

4.2 go get 命令

4.2.1 GO111MODULE=off 时

在 GO111MODULE=off 的情况下,go get 的功能就是一直使用的那样,下载并安装 package 到 $GOPATH/src 中。

4.2.2 GO111MODULE=on 时

在 GO111MODULE=on 的情况下:

  • 如果当前位于一个 module 中,go get 会下载 package 到 $GOPATH/pkg/mod 也就是 go mod 的 cache 中,

    同时会修改 go.mod,把 go get 的 package 添加到当前 module 的依赖中,不管当前 module 实际会不会依赖 go get 的 package。

比如这样:

require (
    github.com/tidwall/gjson v1.3.5 // indirect
    test_mai v0.0.0
)

这里测试 module 的空项目不依赖 gjson,只是在目录下运行了一句 go get,go.mod 中就多了上面这么一行。 当然,再运行一次 go mod tidy,这一行也就被移除了。

关于这一点,golang 的 issues 中的也有一些讨论:链接

4.3 go install 命令

测试目录结构如下

test_go_module
├── go.mod
├── test_mai
│   ├── go.mod
│   ├── mai_pkg
│   │   └── mai_pkg.go
│   └── test_mai.go
└── test_nako
    ├── go.mod
    ├── go.sum
    └── main.go

4.3.1 GO111MODULE=off 时

使用 go install ./test_nako 命令可以编译出 test_nako,并安装可执行文件到 $GOPATH/bin。

4.3.2 GO111MODULE=on 时

如果 test_go_module 目录下没有 go.mod 文件,运行 go install ./test_nako 会提示 go: cannot find main module; see 'go help modules' 错误。

go mod init 命令在 test_go_module 目录下创建 go.mod 文件之后,运行 go install ./test_nako 会提示 go: directory test_nako is outside main module 错误。

只有实际进入 test_nako 目录之后,运行 go install . 目录,才会正确编译出可执行文件并安装到 $GOPATH/bin 目录。

也就是说 GO111MODULE=on 时,只有在 module 的目录下,才能对 module 运行 go install 的命令

目前看到的 GO111MODULE 环境变量的影响就是这些,可能还会有其他的。

五、总结

go mod 确实要比 GOPATH 更加方便,但是 mod 的 cache 默认在 $GOPATH/pkg/mod 目录下, 为了让项目下载下来之后可以直接编译,项目中还是需要保留 vendor 目录。

如果只是把 go mod 作为 vendor 目录的管理工具引入 Silverbolt,只需要在各个子项目下生成 go.mod 进而生成 vendor 目录即可。

如果在编译时使用 GO111MODULE=on 的模式,源码就不需要在 GOPATH 中编译了,编译工具 terry 那边也需要做较大的修改: 包括为 terry 生成 go.mod、编译时不再拷贝源码、修改编译使用的 install 命令等。

Last updated

Was this helpful?