本文内容纲要:

- 1 介绍

- 1.1、go mod是什么

- 1.2、go mod初始化及使用

- 2.1 指定module的根目录并生成go.mod文件

- 2.2 下载并添加依赖到go.mod文件中

- 2.3 查看module下的所有依赖

- 2.4 更新稳定版依赖

- 2.5 更新为指定版本依赖

- 2.6 清理无用的依赖

- 2.7 将依赖复制到项目路径的vendor文件夹中

- 2.8 忽略cache里的包,只使用vendor目录里的依赖进行编译

- 2.9 校验依赖并查看是否有修改

- 3 问题

- 3.1 go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

- 3.2 $GOPATH/go.mod exists but should not

- 4 例子

- 4.1 例子1

- 5 go mod 和 dep 比较

- 一个生成的 go.mod 的示例
1 介绍

1.1、go mod是什么

go mod 是Golang 1.11 版本引入的官方包(package)依赖管理工具,用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。

之前Golang 主要依靠vendor和GOPATH来管理依赖库,vendor相对主流,但现在官方更提倡go mod。

1.2、go mod初始化及使用

下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)

Golang 提供一个环境变量 GO111MODULE 来设置是否使用mod,它有3个可选值,分别是off, on, auto(默认值),具体含义如下:

  1. off: GOPATH mode,查找vendor和GOPATH目录
  2. on:module-aware mode,使用 go module,忽略GOPATH目录
  3. auto:如果当前目录不在$GOPATH 并且 当前目录(或者父目录)下有go.mod文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode。

修改 GO111MODULE 的值的语句是:set GO111MODULE=on 。

GOPATHGOPATH/src/modgo installGOPATH/binGOBIN
go mod download$GOPATH/pkg/mod/cachego mod editgo.modgo mod edit -fmt go.modgo.modgo mod graphgo mod initgo mod tidygo mod vendorvendor/go mod verifygo mod why

注意有几个坑的地方:

go mod$GOPATHGO111MODULEauto$GOPATHongo mod initgo: cannot determine module path for source directory
main.go
$ cat main.go
 
package main
 
 
func main() {
 
  println("Hello world")
 
}
 
$ go mod init
 
go: cannot determine module path for source directory /Users/jiajun/hello (outside GOPATH, no import comments)
 
$ vim go.mod
 
$ cat go.mod
 
module github.com/jiajunhuang/hello
 
$ go mod init
 
go mod init: go.mod already exists
 
$ rm go.mod
 
$ vim main.go
 
$ cat main.go
 
package main // import "github.com/jiajunhuang/hello"
 
func main() {
 
  println("Hello world")
 
}
 
$ go mod init
 
go: creating new go.mod: module github.com/jiajunhuang/hello
 
$ ls
 
go.mod main.go
 
$ cat go.mod
 
module github.com/jiajunhuang/hello

当然,如果在已有代码的仓库里执行是不存在这个问题的。

2 命令

2.1 指定module的根目录并生成go.mod文件

go mod init example.com/hello

2.2 下载并添加依赖到go.mod文件中

go build, go test

2.3 查看module下的所有依赖

go list -m all

2.4 更新稳定版依赖

go get rsc.io/sampler

2.5 更新为指定版本依赖

go list -m -versions rsc.io/sampler
rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
go get rsc.io/sampler@v1.3.1

2.6 清理无用的依赖

go mod tidy

2.7 将依赖复制到项目路径的vendor文件夹中

go mod vendor

2.8 忽略cache里的包,只使用vendor目录里的依赖进行编译

go build -mod=vendor

2.9 校验依赖并查看是否有修改

go mod verify
3 问题

3.1 go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

go mod init

go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

开启go module:

set GO111MODULE=on //windowsexport GO111MODULE=on //linux

3.2 $GOPATH/go.mod exists but should not

GO 1.11或之后模块遇到这个问题:

$GOPATH/go.mod exists but should not

开启模块支持后(set GO111MODULE=on),并不能与$GOPATH共存,所以把$GOPATH从env中移出即可(unset GOPATH),可运行“unset GOPATH && make”。

4 例子

4.1 例子1

go mod初始化:在$GOPATH外建一个文件夹,把个人代码放进去,我的测试代码路径:https://github.com/kevinhao8/go-mod-example。

首先main入口代码所在文件夹创建mod

创建语句 go mod init [module name]

比如我的测试代码 redisTest.go,创建语句就是 go mod init redisTest,成功创建时返回 go: creating new go.mod: module redisTest

此时文件夹下出现 go.mod文件,打开发现只有2行如下,并没有记录依赖库。

module redisTest

go 1.12

此时需要输入go test语句,根据需要的依赖自动生成require,也就是依赖包,此时go.mod多了如下内容(红字是我写的注释,文件里面没有)

require (
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect(有indirect注释的代表间接依赖,没有的代表直接依赖)
github.com/gin-gonic/gin v1.3.0
github.com/golang/protobuf v1.3.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect(这里是版本号+时间戳+hash)
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
)

此时会有如下失败提示,此处为我踩得第一个坑!!!花了挺长时间才解决

build redisTest: cannot load dbredis: cannot find module providing package dbredis

dbredis是我写的私有包,代码是没有问题的,为什么找不到呢?从网上查了一圈,发现私有包如果不想发布到网上,需要手动添加require ,然后replace 进行替换,将私有包指向本地module所在的绝对或相对路径。一般用相对路径更通用。

此时手动将go.mod改为如下,红字为新加

require (
dbredis v0.0.0
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
github.com/gin-gonic/gin v1.3.0
github.com/golang/protobuf v1.3.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/ugorji/go/codec v0.0.0-20190316192920-e2bddce071ad // indirect
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
)

replace dbredis v0.0.0 => ./dbredis

再度运行go test 命令,发现仍有失败提示如下,找不到dbredis文件夹下的go.mod文件。

go: parsing dbredis\go.mod: open E:\code\go-mod-example\dbredis\go.mod: The system cannot find the file specified.
go: error loading module requirements

从网上查资料发现,这种情况下需要给私有包也生成mod,这样整个工程的依赖才能完整。故运行如下命令:

cd dbredis

go mod init dbredis(此处我写的mod名跟package名一致,不知道不一致行不行)

go test

三条命令依次运行通过,dbredis文件夹下的go.mod文件如下:

module dbredis

go 1.12

require github.com/go-redis/redis v6.15.2+incompatible

此时再运行如下命令:

cd ..(回到上层文件夹)

go test

运行通过,不再有报错。运行命令 go build redisTest.go 也能够正常生成redisTest.exe

至此通过mod来管理依赖包基本实现,我们的程序能基本脱离$GOPATH编译。

5 go mod 和 dep 比较
go modGOPROXYgo moddepgo.mod
go.mod
module github.com/my/module/v3 // 这是你的包的声明
 
// require 里是依赖。需要带上路径和版本。
 
require (
 
github.com/some/dependency v1.2.3
 
github.com/another/dependency v0.1.0
 
github.com/additional/dependency/v4 v4.0.0
 
)

本文内容总结:1 介绍,1.1、go mod是什么,1.2、go mod初始化及使用,2.1 指定module的根目录并生成go.mod文件,2.2 下载并添加依赖到go.mod文件中,2.3 查看module下的所有依赖,2.4 更新稳定版依赖,2.5 更新为指定版本依赖,2.6 清理无用的依赖,2.7 将依赖复制到项目路径的vendor文件夹中,2.8 忽略cache里的包,只使用vendor目录里的依赖进行编译,2.9 校验依赖并查看是否有修改,3 问题,3.1 go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules',3.2 $GOPATH/go.mod exists but should not,4 例子,4.1 例子1,5 go mod 和 dep 比较,一个生成的 go.mod 的示例,