go mod是什么

Golang从诞生之初就一直有个被诟病的问题:缺少一个行之有效的“官方”包依赖管理工具。其原因是在Google内部,所有人都是在一个代码库上进行开发的,因此并不是非常需要。但Golang变成一个社区化的工程语言之后,这个问题被放大了。

  1. GOPATH不符合一般开发者习惯,大部分人更习惯maven、node modules之类的方式
  2. GOPATH无法有效的管理版本依赖,没有一个地方能够表明依赖包的具体版本号,无法形成有效的版本配套关系

在Golang 1.5发布了vendor特性之后,社区在vendor基础上开发了很多包管理工具,例如glide, dep(这个最悲催,已经半官方了,结果横刀杀出来一个go mod),等等,具体参见拙文go依赖包管理工具对比 。但说实话,都不是非常满意。

你可能会说dep,glide我用的都挺爽的,有什么不满意的?

其实我不喜欢的是vendor这个特性。开发过前端的同学对node modules一定印象深刻,得益于前端混乱的包管理,一个普通的web前端,其node modules往往非常巨大,而且它是每工程的,也就是说如果有2个前端工程,就会有两份巨大的node moudles,里面有成千上万个文件,常常造成IDE挂死,也非常浪费硬盘。

那么,vendor是不是到后期也会变成这样呢?同样的库,同样的版本,就因为在不同的工程里用了,就要在vendor里单独搞一份,不浪费吗?所以这些基于vendor的包管理工具,都会有这个问题。

相比之下maven这种本地缓存库的管理方式就好很多。

Golang 1.11 版本引入的 go mod ,其思想类似maven:摒弃vendor和GOPATH,拥抱本地库。

先来看看怎么用。

如何使用go mod

在1.11版本引入,尚且是初期版本。考虑向前兼容,目前仍然可以用go get,但最终这个命令是会消失的。

快速开始:

把之前的工程(例如我以前写的netproc)拷贝到$GOPATH/src之外(重点1),创建一个go.mod文件(重点2),文件内容为空即可。

然后在该目录下执行 go build netproc.go ,就可以了。你将看到:

$ go build netproc.go
go: finding github.com/mitchellh/go-wordwrap latest
go: finding github.com/maruel/panicparse/stack latest
go: finding github.com/nsf/termbox-go latest

go命令(‘go build’, ‘go test’, 甚至 ‘go list’)执行时,会自己去修改go.mod文件,执行后go.mod文件新内容如下:

module github.com/silenceshell/netproc

require (
    github.com/gizak/termui v2.2.0+incompatible
    github.com/maruel/panicparse v1.1.1 // indirect
    github.com/mattn/go-runewidth v0.0.3 // indirect
    github.com/mitchellh/go-wordwrap v0.0.0-20180828145344-9e67c67572bc // indirect
    github.com/nsf/termbox-go v0.0.0-20180819125858-b66b20ab708e // indirect
    github.com/spf13/pflag v1.0.2 // indirect
)

可见,go.mod中记录了依赖包及其版本号。

更好的控制

如果想更好的控制,可以修改 GO111MODULE 临时环境变量。

GO111MODULE 的取值为 off, on, or auto (默认值,因此前面例子里需要注意2个重点)。

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

试试:

~/Code/Go/src/github.com/silenceshell/netproc$ GO111MODULE=on go build netproc.go
~/Code/Go/src/github.com/silenceshell/netproc$
~/Code/Go/src/github.com/silenceshell/netproc$ GO111MODULE=off go build netproc.go
netproc.go:7:2: cannot find package "github.com/gizak/termui" in any of:
	/usr/local/go/src/github.com/gizak/termui (from $GOROOT)
	/Users/silenceshell/Code/Go/src/github.com/gizak/termui (from $GOPATH)

on的时候因为我前面已经build过一次,所以直接成功了;但改为off时,会因为找不到包而报错。

注意,go modules 下载的包在 GOPATH/pkg/mod,这就是前面所说的 ‘maven way’;安装的命令仍在 GOPATH/bin

一个简单介绍,更详细的后面使用了再补充。