mod,即module,golang的模块管理工具。Node.js有npm,Python有pip,Golang现在也有了go mod。
起因是,许久不写go了,前几天拿到一个go写的项目,发现里面依赖管理已经不是早前的方式,而多了一张新面孔,go.mod
文件,趁此机会了解学习一下。
原文在这
简介
如果配置过golang开发环境,应该还记得GOPATH这个环境变量,指向一个目录,这个目录下有三个子目录,bin、pkg和src,我们写的代码都在src里,除此之外,所依赖的模块也在src目录下,我们在依赖别人的同时,也可以成为别人的依赖,这是官方给的建议,可能他们觉得一家人就是要整整齐齐的,这是最早期的包管理机制。如果我们开发了10个项目工程,那么这10个项目的所有依赖都在这里面,你中有我,我中有你,随着项目增多,这个目录会越来越大。
但是,每个依赖模块都是有着不同版本,多个工程会存在依赖不同版本的情况,共享GOPATH下的项目,就变得难以操作,于是就衍生出了vendor。每个工程下都有个叫vendor的子目录,直接翻译就是供货商的意思,项目所有的依赖都放到各自的vendor子目录中,互不干涉,互不影响。我的印象中,就是这种管理机制,使用godep命令来管理依赖,这个是当时最实行的方式,毕竟go module还没问世呢。
随着时间发展,技术的进步,go module出来了,它比vendor多了依赖版本记录管理的功能,同时也提升了其他一些vendor体验不好的功能,比如依赖包升级,这些都写在了go.mod文件里,这个文件就和Node.js里的package.json、Python里的requirements.txt功能是一样的。此外,go mod还提供了一个特性,就是项目工程可以不再放在GOPATH/src下了,这样就可以不被其他项目所依赖。
go mod 使用
执行一下go mod,就可以看到命令的说明了
1 | go mod |
常用的有这几个
- go mod init:初始化,一般创建新工程后使用
- go mod tidy:更新项目依赖,没有的下载,没用的删除
- go mod vendor:创建vendor目录,并将依赖复制至此目录
添加新依赖,其中branch指定版本
1 | go get github.com/repo/package@branch |
GO111MODULE 说明
这是个环境变量,有3个可选值:off、on和auto,用来控制go modules功能,看这个名字就知道,是在1.11版本添加的
- off:关闭,编译时仍旧是用老方式,也就是GOPATH/src,或者vendor中的依赖
- on:开启,编译时不会在GOPATH/src下找依赖,而是使用项目中的go.mod文件,依赖包放在pkg/mod下,多项目共享缓存的modules,项目名后面跟着@符号以及版本号
- auto:默认值,在1.13之后,如果工程下存在go.mod文件,则自动开启。1.11中,工程需要在src之外的目录才会开启,以确保兼容
go build -mod 说明
上面有提到,GOPATH/pkg下是生成的中间包.a文件,编译时它的优先级最高,也就是最先被查找,如果找到目标依赖的中间包,则不会再去编译源文件从而再生成.a中间包。
mod有3个值,readonly、vendor和mod。
- readonly:所需依赖不在go.mod中时,或checksum不在go.mod中时,则报错。
- vendor:将使用vendor下的package,而不是pkg/mod下的,不会检查go.mod中的版本
- mod:这个mod就是pkg/mod,也就是用会使用pkg/mod中的package,不存在则下载对应版本的package
附录:go build 和 go install
go build是用来编译、在项目目录下生成可执行的文件,每一个package main都会在相同位置生成一个可执行文件,但不会生成包文件,也就是pkg下的文件。
go install则是用来生成库和工具。没有package main的包,编译后的文件会放到pkg对应的名称下,扩展名.a,如果有package main,就会生成可执行文件,并放到GOPATH/bin下。
所以,二者的相同点是都会生成可执行文件,不同点是生成位置不同,同时instal还会生成中间包文件.a。