Go项目管理 | 青训营笔记

106 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

在编写Go代码项目过程中,经常出现报错提示部分包无法被导入,如下所示,因此学习了Go语言依赖管理的原理,希望能给会遇到同样问题的朋友提供参考。

could not import github.com/jinzhu/gorm (no required module provides package "github.com/jinzhu/gorm")

发展历程

Go的依赖管理经历了三个阶段,GOPATH,Go Vendor和Go Module。

GOPATH

通过go env指令可以查看GOPATH路径:

set GO111MODULE=on
...
set GOPATH=C:\Users\hy\go
set GOROOT=D:\Go
...

在包的依赖引用中,系统查找如下路径:

<GOROOT>/src/
<GOPATH>/src/
<GOPATH>/src/<projectName>/vendor/
<GOPATH>/src/<projectName>/src/ 

Go规定编写自定义GOPATH需要创建文件夹 bin pkg 和src,bin保存项目编译的二进制文件,pkg保存项目编译的中间产物,src保存项目依赖的源代码,在src中可以创建project,并在project中继续创建src。

GOPATH的弊端在于,如果有包的版本升级且前后版本不兼容,可能导致依赖不同版本的项目无法同时构建成功,也即难以实现package的多版本控制。

Go Vendor

对每个项目增加vendor文件夹,将所有依赖包副本放在vendor下,依赖包首先寻址是在vendor,然后再进行查找gopath路径操作。

Go Vendor的弊端在于,项目A依赖的package B 和 package C,B和C依赖同一个包的不同版本,会导致相互兼容存在问题,归根到底vendor不能很清晰的标识依赖的版本概念

Go Module

Go Module 在Go的1.11版本引入,从1.13开始,module模式将是所有开发的默认模式,可以用如下指令查看和修改:go env -w GO111MODULE = on ,go mudule。对于Go语言,依赖管理的三要素为:go.mod用于配置文件,描述依赖;Proxy作为中心仓库管理依赖库,go get/mod是本地工具。

配置文件

go.mod文件组成如图所示:

  • 标识模块指示module下的项目路径。
  • go的原生库版本
  • 单元依赖描述,包括module path +版本号。

gopath和govendor都是源码副本方式依赖,没有版本规则概念,而go.mod为了放方便管理则定义了版本规则,包括语义化版本和基于commit的伪版本。其中语义化版本例如V1.2.3,三个数字中1是major,大版本,不同major可以不兼容;2是minor:新增功能,前后兼容;3是patch。

除了go.mod之外,go命令还维护go.sum的文件,其中包含特定模块版本内容的预期密码散列,go命令使用go.sum文件来确保这些模块的未来下载与第一次下载内容相同,以确保项目所依赖的模块不会意外更改。go.mod和go.sum都应签入版本控制。

go进行版本选择的算法,会选择满足本次构建的最低的兼容版本。

依赖分发

依赖分发主要解决去哪里下载依赖和如何下载的问题。

依赖分发回源:github在go mod的依赖都可以从github中下载。直接使用版本管理下载,无法保证构建稳定,违背了项目托管中心的构建初衷

依赖分发proxy:服务站点proxy,缓存软件内容,版本不会改变,更稳定可靠,可以直接从proxy获取依赖。

依赖分发配置采用goproxy环境变量,参数为服务站点的URL列表,direct表示回源。

常用语句

go mod init创建一个新模块,初始化描述它的go.mod文件。

go build、go test和其他包构建命令根据需要向go.mod添加新的依赖项。

go list-m all列出当前模块及其所有依赖项

go get更改依赖项的所需版本(或添加新的依赖项)。

go mod tidy 删除未使用的依赖项。

参考资料

blog.csdn.net/zkyapple/ar…

go.dev/blog/using-…