前言
最近在看一些go语言相关的书,发现了一个有意思的事情:其中一本书最新印刷的版本是2017年3月,而golang包管理的后起之秀go module
伴随go1.11于2018年8月诞生——因此,书里没有。
有感于golang发展速度之快,且当下项目中go module
、go vendor
(go1.5之后一个热门的包管理工具)交织,甚至时不时看到go path
包管理模式在一些文章中死灰复燃,我想有必要正确梳理一下其中的缘由,以便大家选择合适的包管理模式。
白泽,无脑选择go module
不好吗?过时的东西有必要学吗?
事实上,我认为你可以不用它,但是你得懂为什么这种技术不推荐甚至被弃用,而且你很难定义什么是过时的技术,比如我项目中就用到了vendor。很多golang学习者可能有其他语言的基础,上手go也很快,java有maven,那go必然也有xx包管理工具吧!打开搜索引擎输入go快速入门,安装与项目构建,有的人查到了go path
,有的人查到了govendor
、有的人则是go module
。
这也是我想写一篇文章总结的原因(万一有一天go module也不推荐使用了呢!这种演变的思路值得了解),看过之后保证你能看懂别人文章中写的GOPATH/src、GOPATH/bin、GOPATH/pkg/mod云云,我们开始。
两个命令
go install xxx(下载xxx第三方二进制可执行文件 )
go get xxx(下载xxx第三方依赖包)
下载可执行文件/第三方依赖到本地哪里?不同的包管理工具不同,下面讲。
两个路径
- GOROOT:go的安装目录,类似java的jdk,存放一些内置的开发包和工具。
- GOPATH:go指定的工作空间,用于保存go项目的代码和第三方依赖包。
# mac可以通过go env查看go相关的环境变量,windows类似
go env
GOROOT="/usr/local/go"
GOPATH="/Users/baize/GolandProjects/"
三个包管理工具
go path【不推荐使用】
go path是最早的依赖包管理方式(Go1.0),启用GOPATH模式(注意区分GOPATH模式和GOPATH路径,这是两个语境),要求将所有工程代码要求放在GOPATH/src
目录下。在工程经过 go build xxx
、go install xxx
或 go get xxx
等指令后,会将拉取的第三方xxx依赖包放在GOPATH/src
目录下,产生的二进制可执行文件放在 GOPATH/bin
目录下,生成的中间缓存文件会被保存在 GOPATH/pkg
下。
问题:GOPATH模式下没有版本控制的概念,在执行 go get
的时候,获取的永远是最新的依赖包,下载到GOPATH/src
,如果你有两个工程依赖一个包的v1和v2版本,则会发生冲突,因为 GOPATH
模式下两个工程内依赖的导入路径都是一样的,因此两个工程获取的都是v2版本。
命令:显然GOPATH
模式下go get会将代码拉取到GOPATH/src
,这个模式已经不推荐使用了。
govendor【不推荐使用】
在 Go 1.5版本之后,Go 提供了 GO15VENDOREXPERIMENT
环境变量(Go 1.6版本默认开启该环境变量)和 Govendor
包管理工具,用于将 go build
时的应用路径搜索调整成为当前工程/vendor
目录的方式,有效的解决了不同工程使用自己独立的依赖包目录。编译 Go 代码会优先从vendor
目录先寻找依赖包,vendor
目录如果没有找到,然后在 GOPATH
中查找,都没找到最后在 GOROOT
中查找。
优势:因为将第三方依赖完全和工程整合,使得项目构建速度快,且可以工作在无法连接外网的CI/CD流程中。
问题:放弃了依赖重用,使得冗余度上升
下载:go install github.com/kardianos/govendor(govendor是第三方可执行文件,下载可执行文件用go install,用go get也行,但是会有告警)。
命令:govendor --help
查看所有命令(要先使用go get xxx将xxx依赖下载到$GOPATH/src中,此时go vendor包管理本质是基于GOPATH模式的)
命令 | 功能 |
---|---|
govendor init | 初始化vendor 目录 |
govendor add | 添加包到vendor 目录(相关依赖则是从$GOPATH/src中获取) |
govendor add +external | 添加所有外部包到vendor 目录 |
govendor get | 拉取依赖包vendor 目录 |
然后我在govendor的代码库中看到了下面这段话: