欢迎大家来到IT世界,在知识的湖畔探索吧!
Go Modules是Go 1.11引入的,为了解决Go项目的依赖问题。从go 1.16开始,go modules开始成为Go默认的包依赖管理工具。
go moudle是一组go package的集合
一个Go Module实际上是由一组Go的Package的集合。 构建Go Module的过程需要先确定依赖的其他Go Module的版本、编译包、将编译的目标文件链接到一起。
一个Go项目就是使用go mod创建的一个Go Module,由多个Go package组成,这个项目被保存在一个代码库中(如git)。 也就是说这个代码库中有多个go的package,如https://github.com/grpc/grpc-go这个项目。 每个Go Module根目录中会有一个go.mod文件描述module的元数据信息。
看一下grpc-go这个项目的目录结构:
./grpc-go
├── Documentation
├── admin
├── attributes
├── authz
├── backoff
├── balancer
├── benchmark
├── binarylog
├── channelz
├── cmd
├── codes
├── connectivity
├── credentials
├── encoding
├── examples
├── grpclog
├── health
├── internal
├── interop
├── keepalive
├── metadata
├── peer
├── profiling
├── reflection
├── resolver
├── security
├── serviceconfig
├── stats
├── status
├── stress
├── tap
├── test
├── testdata
├── xds
...
... (省略了根目录里的一些go源码和其他的一些文件)
...
├── server.go
├── go.mod
├── go.sum
└── xds
欢迎大家来到IT世界,在知识的湖畔探索吧!
可以看到grpc-go这个go module就是由一组go pacakge组成,在根目录里有一个go.mod文件,内容如下:
欢迎大家来到IT世界,在知识的湖畔探索吧!module google.golang.org/grpc
go 1.14
require (
github.com/cespare/xxhash/v2 v2.1.1
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/protobuf v1.4.3
github.com/google/go-cmp v0.5.0
github.com/google/uuid v1.1.2
golang.org/x/net v0.0.0-20200822124328-c89045814202
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
google.golang.org/protobuf v1.25.0
)
- go.mod文件的第1行声明了go moudle的路径(path)。grpc-go这个module的path是google.golang.org/grpc。 moudle path有点其他语言中的命名空间的意思,当需要导入go module中的某个包时,需要以module-path/包子目录名称,例如: import “google.golang.org/grpc/codes”导入了google.golang.org/grpc这个go module的codes包。
- go.mod文件第3行的go 1.14用于指明Go的版本,用来说明go.mod文件是使用哪个Go版本中go module语义编写的。因为go mod被直接集成为go的子命令。
- require块中的内容用来配置go module依赖了哪些外部的go module。
go module基于语义化版本
go moudle基于语义化版本,采用v<major>.<minor>.<patch>的格式,例如grpc-go依赖的github.com/google/uuid这个go moudle的版本是v1.1.2。 语义版号的递增规则如下:
- major(主版本号): 当做了不兼容的API修改时,一般是重大架构、技术、功能升级,API已经不兼容原来的版本
- minor(次版本): 当做了向下兼容的功能性新新增,一般是正常的版本、功能迭代,要求API向后兼容
- patch(修订版本号):当做了向下兼容的问题修正,要求API向后兼容
在语义化版本的规范下,使用github.com/google/uuid这个外部依赖的话,grpc-go选择任何v1.x.y都是兼容现在的代码的,例如后续的v1.1.3, v1.2.0。 如果有一天github.com/google/uuid发布了v2.0.0的版本,grpc-go直接修改了go.mod升级了依赖的版本到v2.0.0,如果按照前面的go module依赖导入规则,就会出现编译错误,因为主版本号升级后不承诺API的兼容性。 针对这个问题Go Module给的解决方案是,从主版本号的2开始将主版本号加入到go moudle的path中,具体规则如下:
语义化版本 |
module path |
导入go moudle中的包 |
v0.x.y |
github.com/google/uuid |
import “github.com/google/uuid” |
v1.x.y |
github.com/google/uuid |
import “github.com/google/uuid” |
v2.x.y |
github.com/google/uuid/v2 |
import “github.com/google/uuid/v2” |
v3.x.y |
github.com/google/uuid/v3 |
import “github.com/google/uuid/v3” |
这样如果将项目依赖的外部go moudle的主版本号升级时,就需要切换moudle path和代码中导入package路径,同时对使用的不兼容的API做出修改调整。
关于传递依赖如何选择,例如我们正在开发的A moudle同时依赖了B module和C moudle,而B依赖v1.1.0的D,C依赖v1.2.0的D,D的最新版本是v1.3.0。 使用go mod时,项目A通过传递依赖使用的C的版本将会是v1.2.0。因为按照语义化版本,主版本号相同的话,次版本号越大的其稳定性和安全性应该是更好的,由于B和C传递的版本中选择了次版本号更大的版本。
参考
- https://semver.org/lang/zh-CN/
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/35858.html