go modules初探及踩坑(GO11包管理工具)

kevinhao8 · · 17107 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

1、go mod是什么

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

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

2、go mod初始化及使用

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

  • off: GOPATH mode,查找vendor和GOPATH目录

  • on:module-aware mode,使用 go module,忽略GOPATH目录

  • auto:如果当前目录不在$GOPATH 并且 当前目录(或者父目录)下有go.mod文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode。

修改 GO111MODULE 的值的语句是:set GO111MODULE=on 。!!这个设置是针对全局的还是针对文件夹的临时变量我不清楚,一般保持auto就行

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编译。

3、go mod使用的其他细节

使用go test、go get、go build、go list等命令,Golang 会根据需要更新依赖,也就是require部分。官方建议经常维护这个文件,保持依赖项是干净的,其实意思是要维护其中replace部分,包括私有包的替换以及类似 golang.org/x/text替换成 github.com/golang/text(没法翻墙可以这么改)

我发现mod中依赖包版本跟$GOPATH不一致时,目标版本的依赖包会下载到$GOPATH/pkg/mod中,最终路径还会带依赖包版本号,类似:github.com\go-redis\redis@v6.15.2+incompatible。

更多细节有待之后补充,有问题欢迎向我反馈!!!

4、后续踩坑记录

第二坑:项目中使用了如下开源包:gin-gonic/gin、go-redis/redis、sirupsen/logrus、smallnest/rpcx、spf13/viper,运行go test ./... 时,报如下错误:

go: labix.org/v2/mgo@v0.0.0-20140701140051-000000000287: bzr branch --use-existing-dir https://launchpad.net/mgo/v2 . in E:\code\GoPath\pkg\mod\cache\vcs\ca61c737a32b1e09a0919e15375f9c2b6aa09860cc097f1333b3c3d29e040ea8: exec: "bzr": executable file not found in %PATH%
go: error loading module requirements

报错的字面意思是找不到可执行文件。网上查询找到解决方法,需要更新包引用路径,在go.mod中手动加replace,以下2种均可

labix.org/v2/mgo v0.0.0-20140701140051-000000000287 => gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce

labix.org/v2/mgo v0.0.0-20140701140051-000000000287 => github.com/go-mgo/mgo v2.0.0-20180705113604-9856a29383ce

 

第三坑:引用包跟第二坑相同,运行go test ./... 时,报如下错误:

build dispatcher: cannot load github.com/ugorji/go/codec: ambiguous import: found github.com/ugorji/go/codec in multiple modules:
github.com/ugorji/go v1.1.1 (E:\code\GoPath\pkg\mod\github.com\ugorji\go@v1.1.1\codec)
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 (E:\code\GoPath\pkg\mod\github.com\ugorji\go\codec@v0.0.0-20181204163529-d75b2dcb6bc8)

报错的字面意思是有一个包多个地方引用但版本不一致。网上查询找到解决方法,详见 https://github.com/ugorji/go/issues/279。应该是github.com/ugorji/go这个库的问题,1.1.2版本修复了该问题。

这时需要运行以下命令:

go get github.com/ugorji/go@v1.1.2

再运行go test ./... 就没有报错了


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

17107 次点击  ∙  1 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传