每一个 Golang 初学者都会遇到 GOPATH 和 Go Module 的问题,至少在最近的一两年是这样的。
简单的说,就是由于 Golang 诞生于谷歌,所以早期的项目工程化受谷歌内部开发流程影响很大。谷歌内部不同项目的代码放在一起,方便相互引用。GOPATH 就是这种代码管理方式的体现,所有的包都放在一个固定的开发目录下。
但是外面的世界,可能是受开源生态的影响,我们习惯将代码拆分成不同的包,分散在不通的仓库,需要什么包就导入什么包。所以虽然有一些人一直在吹捧 GOPATH 模式,但是大多数人还是喜欢传统的包模式。
所以在 Go Module 之前,官方或者社区也都有出一些解决方案,其中最有名的是 dep
、vender
。但随着最终方案 Go Module 的确定,他们已经完成了历史使命,而我最近两个月才开始学 Go,当然就跳过他们了。
GOPATH 和 Go Module 的核心问题就是定义我们代码中导入的包在哪里。
我们的包来自什么地方?
- 本地代码目录
GOPATH
目录:~/go
GOROOT
目录:/usr/lib/go
->/usr/lib/go-1.15
, 子目录又都链接到/usr/share/go-1.15/
go get
2 安装包在 GOPATH/src
目录,包导入的查询也是在 GOPATH/src
和 GOROOT/src
下进行。
需要记住的两个点:
- Go 是需要编译的,最后以二进制文件作为输出(我总是会忘记这一点);
- Go 依赖管理的一个重要理念:去中心化。
需要编译,就需要找依赖库
去中心化,就不能是 PyPI,CPAN,Maven 这种,Go 给出的方案是走代码托管平台。
两种模式
- GOPATH 模式
- 早期版本中(1.11 以前1)是 GOPATH 模式,当时只有一个
go get
用于从远程拉代码。- 1.8 之前必须设置
GOPATH
环境变量,1.8 开始可以不设置,默认是~/go
。
- 1.8 之前必须设置
GOPATH
目录相当于就是用户的工作目录,所有的外部包都必须放在这个目录下。
- 早期版本中(1.11 以前1)是 GOPATH 模式,当时只有一个
- Module 模式
- Go 1.11 (2018-08) 开始引入 Module 模式,每个包使用一个
go.mod
文件。
同时加入了GO111MODULE
环境变量,表示是否开启 Module 模式,选项有on
,off
,auto
,默认值是auto
。
auto
的行为:如果不在GOPATH/src
中,并且找到go.mod
文件则使用 Module 模式,否则就是 GOPATH 模式。
比如有个包叫做golang.org/x/tools
,go get
会从 golang.org 下载代码到本地的GOPATH/src/golang.org/x/tools
。 - Go 1.13 (2019/09) 开始,
auto
的行为改为:只要找到go.mod
,就使用 Module 模式。 - Go 1.16 (2021/02) 开始
GO111MODULE
默认值为on
。 - 在可预见的将来,GOPATH 模式会被彻底移除,
GO111MODULE
环境变量也将成为历史。
- Go 1.11 (2018-08) 开始引入 Module 模式,每个包使用一个
在官方的依赖管理工具 go mod
出现之前,还有过 等方案。
参考资料与拓展阅读
- Go Programming Language Wiki, GOPATH
- GZDG-TECH, 给 Gitea 配置 govanityurls,让私有代码仓库中的 go 包支持 go get
-
版本历史
version date go1.17 2021-08-16 go1.16 2021-02-16 go1.15 2020-08-11 go1.14 2020-02-25 go1.13 2019-09-03 go1.12 2019-02-25 go1.11 2018-08-24 go1.10 2018-02-16 go1.9 2017-08-24 go1.8 2017-02-16 go1.7 2016-08-15 go1.6 2016-02-17 go1.5 2015-08-19 go1.4 2014-12-10 go1.3 2014-06-18 go1.2 2013-12-01 go1.1 2013-05-13 go1 2012-03-28 -
go get
的作用是拉取或更新依赖包,支持从 GitHub, BitBucket, Google Code Project Hosting, Launchpad 上下载。
如果本地代码托管服务需要支持go get
的话,好像是需要对服务进行一些调整或者拓展。GitLab 支持。 ↩