go module如何发布v2及更高版本号

直接git打tag就可以发布新版本,但在发布v2以上版本时遇到了一些问题,记录一下。

在本文中,
库(被调用方)路径均以github.com/onelib/mylib代替,
业务程序(调用方)路径均以github.com/caller/myservice代替)


还是按照老方法,直接git打tag,发布。结果在调用方就出现了问题。

更新go mod时直接报错:

require github.com/onelib/mylib: version “v2.x.x” invalid: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2

先说结论:

  • 如果你是库作者,如何处理这个错误,请见本文后续的高版本号(>=v2)如何良好支持go module特性一节。
  • 如果你是库用户,遇到这个错误,那么这属于库作者对go module特性支持不完善,请向其反馈。如果你着急使用,可以参见本文下面的临时解决方案一节。

库用户如何调用【未良好支持go module特性的库】的临时解决方法

库用户临时凑合调用的方法:在go.mod,import时在版本号后面加+incompatible,如

1
2
3
4
5
module github.com/caller/myservice

import (
github.com/onelib/mylib v2.0.0+incompatible
)

(仅作为库未良好支持go module时,调用者可以采用的补丁方案)

但是这样做有缺点,
无法做到同时import多个版本。甚至在不同的文件里都不行,即使你一个文件或目录里只用了一个版本,整个项目也只能导入一份版本。
这样就不能让旧代码仍然使用旧版本,而必须整个项目一起升级到新版,所以有时会造成旧代码的破坏
同时一些IDE可能由于不识别这种版本号标识而报错。

如果我们仅仅是调用者而非编写者,而实际编写者又没有支持go module时,在确定不会造成旧版本代码破坏后,我们就可以使用这种方案临时解决调用问题。

如果我们就是库的编写者,请继续看下节。

库作者发布高版本号(主版本号>=v2)如何良好支持go module特性

如果你是库作者,更完美的解决方案是:

将库的go.mod中的moulde名称后面增加版本号/vx


module github.com/onelib/mylib
->
module github.com/onelib/mylib/v2

注意,文件结构不需要做任何改变,不需要建立v2或者vn文件夹,增加的“/vx”仅仅用于require/import时区分主版本号。

调用时也仍以库文件中声明的package xxx为准来进行xxx.FuncX()调用,而与go.mod中module怎么写的无关。

而后重新在git中打tag v2.x.x,发布。调用方就可以愉快地使用了。

代码示例:

go.mod

1
2
3
4
5
module github.com/onelib/mylib/v2

import (
// ...
)

文件目录结构无需改变。

调用方使用方法见下节。

这就是module发布者根据go module特性处理版本问题的正确方法。
同时,库作者请参照下节,告知库用户在require/import时加上合适的主版本号后缀。

库用户如何调用【有良好支持go module特性的库】的方法

库作者在正确支持go module特性后,库用户(调用方)的注意事项:

  1. go.mod文件中require path需要同样在结尾加上/vx。
    require github.com/onelib/mylib/v2 v2.x.x
  2. 代码(.go文件)中的import path需要同样在结尾加上/vx。
    import github.com/onelib/mylib/v2

这样,调用者可以在同一项目下import同一模块的多个不同主版本了。

但同一主版本、不同子版本仍然不能共存,这是因为由golang采用的语义化版本号(Semantic Versioning)可知,同一主版本应当是向下兼容,因此同一主版本的高子版本应当能兼容低子版本的功能。

例外:v0和v1似乎还是只能导入一个。有了v1就不能再用v0。
不过在语义化版本号中,v0代表试验的初期不稳定版本,有了v1就基本不会再有用v0的需求,问题不大。

代码示例:

go.mod

1
2
3
4
5
6
module github.com/caller/myservice
require (
github.com/onelib/mylib v1.0.0
github.com/onelib/mylib/v2 v2.1.3
github.com/onelib/mylib/v3 v3.2.1
)

在同一项目的不同的代码文件中使用同一库的不同主版本:

代码文件1.go

1
2
3
4
   import "github.com/onelib/mylib"
func f1() {
mylib.FuncX()
}

代码文件2.go

1
2
3
4
   import "github.com/onelib/mylib/v2"
func f2() {
mylib.FuncX()
}

代码文件3.go

1
2
3
4
   import "github.com/onelib/mylib/v3"
func f3() {
mylib.FuncX()
}

在同一项目的同一代码文件中使用同一库的不同主版本:
(这个需求有点少见,不过也能实现,如果各主版本包名冲突,import时指定别名即可)
代码文件x.go

1
2
3
4
5
6
7
8
9
10
11
package main
import (
myliba "github.com/onelib/mylib"
mylibb "github.com/onelib/mylib/v2"
mylibc "github.com/onelib/mylib/v3"
)
func main() {
myliba.FuncX()
mylibb.FuncX()
mylibc.FuncX()
}
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信