记一次go module的坑
一、背景
事情是这样的,因为小马本次要写一个go项目。但是因为一些权限问题,一些依赖包在内网小马获取不到,于是只能求助大大。大大给的策略就是他先把所有的依赖包go mod,然后go mod vendor迁移到项目目录vendor下进行本地依赖载入即可,也就是使用 go build -mod=vendor来编译即可。一切似乎看起来还是那么完美。然后正要起飞,直接翻车,现场如下。【这里插播一条发现,就是使用golang IDE go build 和使用命令行go build 的区别在于前者不会生成.exe文件】
二、翻车现场
将大大go mod vendor完的包pull到本地,只要编译就会发生如下错误(以下省略了一部分类似的报错)。其实是 go.mod内的所有依赖包都报错。
dD:\Go\bin\go.exe build -o C:\Users\lihi\AppData\Local\Temp\___go_build_main_go.exe D:\gok\word\main.go #gosetup
go: inconsistent vendoring in D:\gok\word:
git.code.oa.com/components/l5@v0.3.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
github.com/golang/protobuf@v1.4.3: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
golang.org/x/net@v0.0.0-20201216054612-986b41b23924: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
run 'go mod vendor' to sync, or use -mod=mod or -mod=readonly to ignore the vendor directory
Compilation finished with exit code 1
三、现场勘察
大大说他的本地编译是正常的。不得不怀疑是不是因为大大本地gopath还有一份包依赖的原因,然而经查并不是这个问题。翻阅了网络上的大部分资料无果,网络上要么是说是因为识别不到包,按照提示重新go mod vendor一下就可以了。小马蛮试了一下,不出所料必然地报远程报获取不到呢,IDE的报错定位其实是不准确的。再次检查vendor/modules.txt文件,没有问题,无果。 于是开始质疑golang IDE 的版本支持问题,无果。看了下go.mod文件中写着go 1.14,也没错呢,小马用的GO SDK正是1.14.4版本。敲出go env 查看环境配置,GO111MODULE=on,因为环境变量是auto,但是go到一定版本后默认是on,也没问题,无果。那问题出在哪呢?由于没有依赖包拉取权限,只能再次求助大大,大大表示也很奇怪,一番折腾,于是问题得到解决。【这里插播一条好玩的东西,就是GO111MODULE为什么是GO111呢,因为其实1.11版本开始支持MODULE的】
四、问题解决
结论是:因为大大go mod的时候用的是go 1.13,而我编译的时候用的 1.14,所以就报了这个奇怪的错误。you what?直接懵逼。但是为啥go.mod文件中写的版本要求是1.14,而大大用1.13也编译得好好的。
这是个大坑,掉进坑里自己扑腾了一天!!希望大家谨慎入坑。
五、小本本
爬坑一小时出坑一秒钟,每一次的爬坑都是充满着十八般绝技。奇怪的姿势又增加了。
go运行方式有哪几种?
gopath模式, 配置gopath目录,一般目录下有三个目录:bin,pkg,src。项目代码放在src中。先在gopath的vendor中寻找依赖包。
go mod模式, 是先在项目目录的vendor下寻找依赖包,然后在gopath的pkg/mod下寻找依赖包。如果都没有则远程下载到默认gopath的pkg/mod下,该模式不认src目录。也可以强制用go build -mod=vendor 或者-mod=mod来决定是否直接使用本地的vendor依赖包直接运行编译,忽略go mod中的依赖,不识别远程依赖包(这一点非常适合包的随意拷贝分发,当然也是本次没有依赖包权限的解决方法)。
如果GO111MODULE是auto则根据项目目录位置和是否含有go.mod文件来决定使用什么模式。如果是GO111MODULE=off则使用gopath,如果是on则使用module模式。gopath模式下的src目录下不能有go.mod文件,否则报错。
一些go mod命令记录备用,国内的资料并不多(注意go mod 命令在 $GOPATH 里默认是执行不了的,因为 GO111MODULE 的默认值是 auto。默认在$GOPATH 里是不会执行, 如果一定要强制执行,就设置环境变量为 on。):
查看环境设置:go env
查看go版本:go version
设置顶级vendor作为依赖:go env -w GOFLAGS="-mod=vendor" 查看env 是GOFLAGS=-mod=vendor,取消:g o env -w GOFLAGS="-mod=";
指定gomod编译 模式:go build -mod=vendor
go mod download下载模块到本地缓存,缓存路径是$GOPATH/pkg/mod/cache
go mod edit是提供了命令版编辑go.mod的功能,例如go mod edit -fmt go.mod会格式化go.mod
go mod graph把模块之间的依赖图显示出来
go mod init初始化模块(例如把原本dep管理的依赖关系转换过来)
go mod tidy增加缺失的包,移除没用的包
go mod vendor把依赖拷贝到vendor/目录下
go mod verify确认依赖关系
go mod why解释为什么需要包和模块