最近遇到了一个很诡异的问题,项目中依赖了gin和viper之后竟然提示错误
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 (D:\workspace\go\pkg\mod\github.com\ugorji\go@v1.1.1\codec)
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 (D:\workspace\go\pkg\mod\github.com\ugorji\go\codec@v0.0.0-20181204163529-d75b2dcb6bc8)
直接从字面看似乎是符号冲突,类似于C/C++中引入了两个不同的符号,但是go module以后包都是统一放到$GOPATH/pkg
下的不应该会出现类似问题。
通过go mod graph
可以查看具体依赖路径
github.com/spf13/viper@v1.3.2 github.com/ugorji/go/codec@v0.0.0-20181204163529-d75b2dcb6bc8
github.com/gin-gonic/gin@v1.3.1-0.20190120102704-f38a3fe65f10 github.com/ugorji/go@v1.1.1
可以看到viper和gin分别依赖了github.com/ugorji/go
和github.com/ugorji/go/codec
应该是go把这两个path当成不同的模块引入导致的冲突
这里很奇怪的地方是,为什么github.com/ugorji/go/codec
作为一个子目录也会被当成模块引入
到了github.com/ugorji/go
上看发现还真有类似的问题
首先我们看一下这个包是干什么的
根据首页描述应该是个处理msgpack
编码协议的包,这里有一点值得注意
github.com/ugorji/go
仓库根目录并没有文件,所有实现在github.com/ugorji/go/codec
下
再回头看看这个包的历史,基本可以了解这个问题了
github.com/ugorji/go/codec
时,go会根据path找到github.com/ugorji/go
这个仓库并将其作为一个包引入这就对应这上面的
github.com/ugorji/go v1.1.1
github.com/ugorji/go/codec
作为一个模块,和前面的github.com/ugorji/go
认为是两个模块了.这时如果两个包分别使用了这两个版本就会导致上面的问题+ require github.com/ugorji/go v1.1.2
这时候依赖github.com/ugorji/go@1.1.1
的老模块和依赖github.com/ugorji/go/codec@1.1.2
的新模块一起使用时,由于上面的变更,整个项目里依赖的github.com/ugorji/go
模块会使用较新的1.1.2.
因为1.1.2的时候codec目录下已有go.mod,因此github.com/ugorji/go
下面不会有任何文件,就不会导致符号冲突
这时对go来说回到了v1.1.1的时候,如果同时有两个依赖模块依赖v1.1.2和v1.1.4时同样会出现符号冲突的问题
在gopath时代没有版本的概念,大家都在一个gopath下,符号基于路径,因此没有符号冲突的问题
在vendor时代,vendor下的包会被加上$package\vendor
前缀,因此项目中不同的包依赖相同模块的不同版本时也不会冲突
到了module时代,所有的依赖包都在$GOPATH/pkg
下,虽然存储的时候分了版本,但是链接时并没有,因此任何代码不同版本只有最新的一份.
可能这些描述看着很别扭,我们先整理一下go module中的一些术语:
上面的问题本质就是由于作者的疏忽造成了存在两个模块github.com/ugorji/go
和github.com/ugorji/go/codec
同时这两个模块又存在相同的包,导致符号冲突
这些问题在golang官方的wiki中都有描述.建议大家在使用go module之前也详细阅读一下官方wiki
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。