Golang Go语言中忘掉 GOPATH,迎接 Go modules,进入 Go 项目依赖库版本管理新时代
Golang Go语言中忘掉 GOPATH,迎接 Go modules,进入 Go 项目依赖库版本管理新时代
Go SDK 1.13 测试版马上就要发布了。从此版本开始,Go modules 依赖库版本管理特性将正式开始推荐使用。本文将解释一些和 Go modules 相关的一些命令和概念。
Module (模块)定义为一些 Go 代码包的集合。通常体现为一个含有若干代码包的目录。每个模块可以发布一系列版本。版本号使用semver (语义化版本)表示。一个模块可能依赖于其它若干模块;准确说来,是依赖于其它若干模块的各自的某个具体版本。每个模块可以在自己的根目录下的go.mod
文件中指定其所依赖的各个模块的具体版本。
如果你所维护的某个模块尚未使用 Go modules 管理依赖,你可以打开一个命令行终端,进入此模块根目录,运行下面这条命令将此模块转换为一个使用 Go modules 管理依赖的模块。
go mod init host.prefex/mypkg
其中,host.prefex/mypkg
为其它包引入此模块中的包时的引入路径的前缀。常常地,host.prefex
为github.com
等源代码托管网站;mypkg
常为 user/project
这种形式。当然,你也可以将你自己的域名 my.website
用做引入路径的前缀(host.prefex
)。但是这时如果不能从引入路径my.website/mypkg
中判断出此代码包使用何种源代码版本管理工具(比如 git/hg/svn 等),则my.website
网站必须响应 https://my.website/mypkg?go-get=1
HTTPS 请求( HTTP 也可以但不推荐),并在在 HTML 的返回体中的<head>
部分包含一个<meta>
标签来指名具体到哪里下载此模块。(本公众号将另开一篇文章详解自定义域名引入路径。)
当 go.mod 文件已经创建出来之后,我们可以在此文件中手动指定此模块所要依赖的其它模块和这些以来模块的版本号(版本号必须制定但可以使用伪版本号,比如 <v1.12.3
、>=v1.5.6
、latest
和分支名master
等)。我们也可以运行 go build 和 go test 等命令来自动发现并且在go.mod
文件中加入依赖模块和它们的具体版本。手动指定的伪模块版本号将被go build
等命令更改为确切的版本号。其中
latest
伪版本号将被解读为最新正式发布版本,正式发布版本是标号为形如vX.Y.Z
的语义化版本( semver,X
/Y
/Z
均为整数数字)。- 分支名伪版本号将被解读为指定分支的最新提交。
- 而
<v1.12.3
将被解读为v1.12
系列版中最大的小于v1.12.3
的版本。
当使用源代码版本管理工具时,一个 tag 的名称将被视为一个版本号。形如 v1.2.3-pre1
的预发布版本不属于正式版本。(关于模块的版本匹配规则,本公众号将另发一篇文章详述。)
go build
等命令将下载并缓存尚未缓存的依赖模块的版本代码,并将各个模块(包括直接和间接依赖)的哈希存储在go.sum
文件(和go.mod
文件处于同一目录)中。
在一个模块目录下运行 go get a.b.c/x/[email protected]
将在此模块的go.mod
文件中加入一个依赖。
默认情况下,go build
等命令将访问 sumdb ( Checksum Database,默认值为 https://sum.golang.org/
)验证各个直接或者间接依赖模块的哈希值是否和各个go.sum
中记录的哈希值相匹配。如果不匹配,很可能某些环节出了问题(比如下载的模块代码被人恶意更改了)。(关于 sumdb,本公众号将另发一篇文章详述。)
一般说来,go.mod
文件中只记录当前模块的直接依赖。每个依赖体现为一条require
或者replace
指令。比如
module my.website/cmd/myprogram
require github.com/boltdb/bolt v1.3.0
replace my.website/mypkg github.com/myname/myproject v1.0.0
其中的 replace
指令表示,当遇到引入路径前缀为 my.website/mypkg
的代码包时,真实的下载的代码包为处于路径 github.com/myname/myproject
的v1.0.0
版本的模块下的相应代码包。
如果你的一个旧项目是使用其它流行第三方工具(比如 deps 和 glide 等)来管理包依赖的,则在此项目下运行 go mod init host.prefex/mypkg
命令将自动将此项目转换为一个使用 go modules
管理依赖的项目。
如果你的一个新项目需要依赖于一个当前正使用其它流行第三方工具来管理包依赖的库,则请到此库的根目录下运行以下 go mod init a.b/c
命令(引入路径可任意),然后将生成的go.mod
中的所有require
指令复制到你的新项目下的go.mod
文件中。(至少对于目前的 Go SDK 1.12 是如此,以后的 Go SDK 版本可能会对此过程进行改进。)
一些其它的和 modules 相关的常用命令和命令选项:
go list -m all
列出所有的(包括直接的和间接的)将在 go build 中使用的各个模块和它们的具体版本号go list -u -m all
列出所有的(包括直接和间接)使用的各个模块目前可用的小更新或者补丁版本号go get -u or go get -u=patch
将目前所有的(直接和间接)依赖的模块的版本号更新到最新可用的小更新或者补丁版本号。go mod tidy
从go.mod
中删除目前已经不再使用的依赖模块和加入其它操作系统和架构所需的依赖go mod vendor
将所有依赖放入当前模块下的vendor
子目录中go build -mod vendor
使用当前模块下的vendor
子目录中的依赖代码(而不是缓存中依赖模块代码)来编译构建
本文首发在微信Go 101公众号,欢迎各位转载本文。Go 101公众号将尽量在每个工作日发表一篇原创短文,有意关注者请扫描下面的二维码。
关于更多 Go 语言编程中的事实、细节和技巧,请访问《 Go 语言 101 》项目 https://github.com/golang101/golang101。
更多关于Golang Go语言中忘掉 GOPATH,迎接 Go modules,进入 Go 项目依赖库版本管理新时代的实战教程也可以访问 https://www.itying.com/category-94-b0.html
还没搞明白怎么继续 import GOPATH 里面的包
更多关于Golang Go语言中忘掉 GOPATH,迎接 Go modules,进入 Go 项目依赖库版本管理新时代的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
“ import GOPATH 里面的包” 和 “ import 模块中的包” 两者时不兼容的
一直关注,支持
看起来不错,找个时间研究下,gopath 实在太恶心了
多谢分享
建议向 maven 学习,Go modules 依旧难用。。。
借楼安利一波 https://smallwhite.ml/pub/go/deploy-go-modules-proxy.html
部署 go modules 代理
用了有一段时间了,依旧很难用,碰到有的包需要 1.12 版本,有的包开了代理也下载不了,下载也没个进度条,几乎每天都在以为卡死了,不停的 go mod tidy 很是影响心情
设置 GOPROXY 之后就和 maven 一样了。国内应该很快会出现一些 goproxy 服务。
不过最好还是自行解决 https_proxy 代理问题为好。
> 有的包开了代理也下载不了
这个应该是代理的问题。
另外,从 Go 1.13 开始,哈希检查也可能会对一些 go 命令的响应时间有所影响。希望 sum.golang.org 能够在国内访问,不然国内的 goproxy 服务没人敢用。我们可以将 GONOSUMDB 环境变量设为 off 来关闭哈希检查。
JFROG 有个 Go center 的代理,还凑合着用吧
蛋疼的一点是:
在 GOPATH 里面使用 go mod,即使在 GoPath 里面有要使用的 pkg…
在构建等等的时候 go 还是会去 web 上下载…
也就是说完全不管当前目录下面有没有 相应的 PKG…
也不管你有没有修改要使用的 pkg…老子就是要下载人家发布的包…
超级蛋疼…
感觉和 maven 相比差的不少…
摆脱 GOPATH 依赖是很好,但是当项目中既包括需要科学上网访问的包,又包括私有 repo 上的包时…go mod tidy 就变成很蛋疼的事情了.
不走代理, 外网的包拉不下来. 走 GOPROXY 代理, 私有 repo 的包拉不下来. 最终只能通过自建 HTTP 分域名代理来解决…
我一直觉得 GOPATH 没有错,只是我们依然停留在有版本号的时代。
go modules 会出莫名其妙的问题
还不如 dep 稳定好用
> GOPROXY 代理, 私有 repo 的包拉不下来.
设置 GONOPROXY=private.domain/* ?
11 开始用,不太重度的使用体验还不错,重度使用仁者见仁智者见智
有我 大 PHP 的 composer 好用 me 哈哈哈
并不是的,实际上 GOSUMDB 本身(比如 sum.golang.org )也是可以被 GOPROXY 所代理的,而且由于 GOSUMDB 的设计所以即使代理了也是很安全的,你看 https://go.googlesource.com/proposal/+/master/design/25530-sumdb.md 就知道了,所以无论国内还是国外的代理都是可以放心使用的。推荐我在用的一个支持代理 GOSUMDB 的 GOPROXY,速度很快: https://github.com/goproxy/goproxy.cn<br>export GOPROXY=<a target="_blank" href="https://goproxy.cn" rel="nofollow noopener">https://goproxy.cn</a><br>export GOSUMDB=<a target="_blank" href="https://sum.golang.org" rel="nofollow noopener">https://sum.golang.org</a><br>
这样设置就安全了,放心使用吧。
> 实际上 GOSUMDB 本身(比如 sum.golang.org )也是可以被 GOPROXY 所代理的
这个倒没注意。我再研究一下。
嗯,没有绝对地安全。不过能防止代理们篡改信息就是了,因为即使是发布后缓存签名也是需要 GOSUMDB 先回源拉去一次的,代理们还是没法儿做手脚。
正在学习使用, 之前碰到网络问题(但我看不出是网络造成的), 各种墙真的好蛋疼. 还有总算可 import 相对路径了.
确实,随着Go语言的不断发展,Go modules已经成为管理Go项目依赖库版本的主流方式,它让我们可以更加便捷和高效地管理项目依赖。
Go modules是Go 1.11版本引入的依赖管理系统,从Go 1.13版本开始被推荐使用。它解决了GOPATH模式下依赖管理混乱的问题,让我们可以更加清晰地了解项目所依赖的库和版本。通过go mod命令,我们可以轻松地初始化模块、添加依赖、下载依赖、整理依赖等。
使用Go modules,我们可以将依赖库下载到GOPATH下的pkg/mod文件夹中,并且每个依赖都会带有版本号,这样可以确保项目在不同环境下使用相同版本的依赖库,从而避免版本冲突和兼容性问题。
同时,Go modules还支持语义化版本号(semver),让我们可以更加直观地了解依赖库的版本变化和兼容性。此外,通过go.mod和go.sum文件,我们可以清晰地记录项目所依赖的库和版本,以及依赖库的依赖关系,这样可以确保项目的可重复构建性。
因此,对于Go语言开发者来说,掌握Go modules的使用是非常重要的。它不仅可以提高我们的开发效率,还可以确保项目的稳定性和可维护性。