问题症状
我们使用 jenkins 脚本执行 go build ,用来构建线上服务器使用的二进制文件。构建过程中有这样一个步骤:
go mod vendor
该步骤将以 go.mod 文件中写明的包和版本为准下载第三方依赖并保存到本地的 vendor 目录。下载过程中将校验 go.sum 中的 hash 值是否同文件 hash 一致。
在实际执行中,遇到这样的错误:
internal error: failed to find embedded files of github.com/marten-seemann/qtls-go1-18: //go:build comment without // +build comment
排查经过
- 通过 qtls-go1-18 的仓库名可以观察到问题可能跟 go 1.18 的版本有关。
- 打开依赖的 github 仓库可见简介:
Go standard library TLS 1.3 implementation, modified for QUIC. For Go 1.18.
而我们构建的环境 go env 输出的版本为 1.16 - 在 go 1.18 的 release notes 中查找相关信息:
//go:build lines报错的意思是
Go 1.17 introduced //go:build lines as a more readable way to write build constraints, instead of // +build lines. As of Go 1.17, gofmt adds //go:build lines to match existing +build lines and keeps them in sync, while go vet diagnoses when they are out of sync.
Since the release of Go 1.18 marks the end of support for Go 1.16, all supported versions of Go now understand //go:build lines. In Go 1.18, go fix now removes the now-obsolete // +build lines in modules declaring go 1.18 or later in their go.mod files.
For more information, see https://go.dev/design/draft-g...
//go:build
(1.18 版本支持) 必须同 // +build
一起出现。至此确认问题原因。解决办法
业务代码并没有直接用到 qtls 包,且并没有直接依赖 qtls-go1-18 对应的 go 版本。此库为非直接依赖引入的,需要找出是那个包引入了这个依赖。
go mod why github.com/marten-seemann/qtls-go1-18
可以查看是谁引入该依赖。从输出可以看到:
# github.com/marten-seemann/qtls-go1-18
git.mycompany.com/group/projecta
git.mycompany.com/group/projectb
github.com/smallnest/rpcx/client
github.com/lucas-clemente/quic-go
github.com/marten-seemann/qtls-go1-18
通过
go mod graph
可以看到具体那个包的那个版本引入的最终确认是 quic-go 的 0.27 引入的。
【执行 go vendor 时第三方包 go 版本冲突问题的解决方法】在 go.mod 中排除掉 quic-go 0.27 即可。在 go.mod 中加一行。
exclude lucas-clemente/quic-go v0.27.0
总结和其他
- 为什么 go mod vendor 会更新版本,理论上只会使用 go.mod 中制定的版本;
- build 机器不需要 go mod vendor ,直接 go mod download 即可;
- go mod vendor 同 go mod download 在依赖管理上有什么不同?
推荐阅读
- golang网络数据交换
- go reflect struct (go反射与struct结构体)
- 用原生Go写一个自己的博客-搭建项目
- 极客时间-Go进阶训练营|全新升级第4期|完结无密
- golang操作clickhouse使用入门
- Go的省略符 omitempty和 - 两种方式详解
- 使用Shifu在OpenYurt集群中接入RTSP协议摄像头
- golang metrics各个指标含义
- 如何用Shifu来接入一个私有驱动的物联网设备