前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >​从一个模块冲突问题学习go module

​从一个模块冲突问题学习go module

原创
作者头像
王沛文
修改2019-04-23 15:04:50
11.9K4
修改2019-04-23 15:04:50
举报
文章被收录于专栏:王沛文的专栏王沛文的专栏

问题

最近遇到了一个很诡异的问题,项目中依赖了ginviper之后竟然提示错误

代码语言:txt
复制
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可以查看具体依赖路径

代码语言:txt
复制
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/gogithub.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

再回头看看这个包的历史,基本可以了解这个问题了

  1. v1.1.1 这个tag时,并没有使用go.mod,因此当使用了go module的包引用github.com/ugorji/go/codec时,go会根据path找到github.com/ugorji/go这个仓库并将其作为一个包引入

这就对应这上面的

代码语言:txt
复制
   github.com/ugorji/go v1.1.1
  1. e253f1f20942cb6dc505e504e8bbba4b7f434cb2这个提交之后,作者在codec目录下添加了go.mod文件.这时候go就把github.com/ugorji/go/codec作为一个模块,和前面的github.com/ugorji/go认为是两个模块了.这时如果两个包分别使用了这两个版本就会导致上面的问题
  2. v1.1.2 这个tag时作者修复了上面的问题,方法是在codec目录的go.mod下添加了依赖
代码语言:txt
复制
+ 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下面不会有任何文件,就不会导致符号冲突

  1. v1.1.4的时候 作者又把codec下的go.mod删除了,而在根目录下新增了go.mod

这时对go来说回到了v1.1.1的时候,如果同时有两个依赖模块依赖v1.1.2和v1.1.4时同样会出现符号冲突的问题

总结

在gopath时代没有版本的概念,大家都在一个gopath下,符号基于路径,因此没有符号冲突的问题

在vendor时代,vendor下的包会被加上$package\vendor前缀,因此项目中不同的包依赖相同模块的不同版本时也不会冲突

到了module时代,所有的依赖包都在$GOPATH/pkg下,虽然存储的时候分了版本,但是链接时并没有,因此任何代码不同版本只有最新的一份.

可能这些描述看着很别扭,我们先整理一下go module中的一些术语:

  • module 模块。有go.mod文件时,则是go.mod文件所在的路径,对于没有go.mod文件的则是仓库根目录
  • package 包。包就是go文件中import的东西,按路径区分

上面的问题本质就是由于作者的疏忽造成了存在两个模块github.com/ugorji/gogithub.com/ugorji/go/codec同时这两个模块又存在相同的包,导致符号冲突

这些问题在golang官方的wiki中都有描述.建议大家在使用go module之前也详细阅读一下官方wiki

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 分析
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档