我有一个基于GOPATH的项目,目前在Fedora上构建如下:
sudo dnf install golang-etcd-bbolt-devel golang-x-sys-devel golang-x-text-devel
GOPATH=$HOME/go:/usr/share/gocode go build
我的项目(gonzofilter)实现了一个命令行实用程序,因此源文件位于主包中(即它们有package main
声明)。
在Fedora 34及以后的版本中,Go语言似乎取消了对构建GOPATH风格项目的支持,人们不得不使用Go语言的模块:
go build
go: cannot find main module; see 'go help modules'
Go语言的这篇博文在某种程度上涵盖了我的情况(-〉“没有依赖管理器”),但它没有明确提到如何处理主包项目或发行版提供的依赖。
那么,如何迁移这样的项目呢?
我该如何让Go语言/go mod tidy
在/usr/share/gocode
下查找我的依赖项呢?
**编辑:**准确地说:Fedora 34自带的Go语言1.16只是将GO111MODULE
的默认值从auto
修改为on
,因此,用户仍然可以通过设置GO111MODULE=auto
来恢复原来的行为。
然而,Golang的开发者们已经明确表示,他们希望在Go语言1.17中放弃对GOPATH风格项目的支持:
我们计划在Go语言1.17中放弃对GOPATH模式的支持,换句话说,Go语言1.17将忽略GO 111 MODULE,如果你的项目不是在模块感知模式下构建的,现在是时候迁移了。
**更新2023-02-19:**截至Go 1.19.5(Fedora 37),GO111MODULE=off
仍然适用于构建GOPATH风格(即非模块化)的项目。
export GOPATH=$HOME/go:/usr/share/gocode GOPROXY=off GO111MODULE=off
go build helloworld.go
显然,Go团队调整了他们的GO 11 MODULE弃用计划,没有了targeting any new future release for removal, yet。
4条答案
按热度按时间8yoxcaq71#
您可以在生成的mod文件中使用replace关键字显式定义引用本地模块。
replace packagename => /usr/share/gcode
esyap4oy2#
理想情况下,发行版应该将安装的依赖项打包到与
GOPROXY
协议兼容的布局中,然后您就可以适当地设置GOPROXY
并运行go mod tidy
来使用安装的依赖项。然而,据我所知,目前还没有发行版真正提供
GOPROXY
树。下一个最好的选择是使用
replace
指令自己连接替换。go mod tidy
已经知道在replace
指令中找到的版本比其他版本更受欢迎,所以它应该满足以下要求:但是,注意
replace
指令要求目标包含一个显式的go.mod
文件,因此只有当您的依赖项已经包含显式的go.mod
文件,或者您的发行版打包程序已经将它们作为补丁添加以支持此用例时,此指令才起作用。请注意,使用这些
replace
指令,您的构建将无法随时间推移而重现或重复:如果你改变了你的依赖的发行版安装的版本,那么go build
的含义也会悄悄地改变以使用那些不同的(并且可能不兼容!)版本。因此我建议您不要这样做,而是使用
go get
和/或go mod tidy
从上游或从公共模块代理(如proxy.golang.org
)获取您想要的特定模块版本。如果您担心上游篡改,请注意Go语言项目的
go
命令的official binary distribution--以及从原始源代码构建的go
命令--在默认情况下会根据www.example.com上的可审计公共数据库自动验证已下载模块的校验和https://sum.golang.org;然而,Fedora发行版的go
命令在默认情况下禁用校验和数据库。l3zydbqr3#
将这样的GOPATH项目迁移到Go语言模块感知的项目的一种方法如下:
首先,手动创建具有直接依赖项的
go.mod
:我从当前系统中获取了最低版本:
现在的问题是,我们不能简单地告诉模块感知的Go语言工具在它们所在的文件系统路径
/usr/share/gocode/src
下查找这些模块。有一个
replace
指令可以添加到我们的go.mod
文件中,为单个依赖项设置查找路径,例如:但是,
go build
仍然不使用来自/usr/share/gocode
的 * 间接 * 依赖项,例如,由golang-x-text-devel
依赖的包提供的依赖项。在这个例子中,go build
确实找到了/usr/share/gocode/src/golang.org/x/text/go.mod
,但该文件不包含任何replace
指令。因此,这失败了:
要解决这个问题,我们必须为所有间接依赖项添加replace指令行。
当然,手动执行此操作既繁琐又容易出错。
因此,我们可以使用一个小shell一行程序自动执行此操作:
我们从
go.mod
文件开始:然后,以下定点迭代将添加依赖项,直到生成成功:
这将为该示例项目生成以下require指令:
x759pob24#
另一种将Go语言指向系统级可用依赖项的方法是利用Go语言的模块供应支持:这意味着通过符号链接模块文件路径,创建一个最小的
vendor/modules.txt
并用-mod vendor
编译。因此,对于
-mod vendor
,Go build不会尝试下载任何需要的模块,而是在vendor/
目录中查找它们。人们可能会尝试创建一个从
vendor/
指向/usr/share/gocode/src
的符号链接(所有golang-...-devel
发行版都安装在/usr/share/gocode/src
中),但这并不起作用,因为-mod vendor
还需要另一个模块描述文件,即vendor/modules.txt
。因此,除了一些更具体的符号链接,我们必须创建一个适当的
modules.txt
当使用vendoring功能:首先,创建所有子级符号链接:
然后,要创建
vendor/modules.txt
:执行这些命令后,示例项目的vendor目录如下所示:
然而
go.mod
是非常小的,即它不包含任何replace指令:这就足以让
成功。
请注意,间接依赖项(如
golang.org/x/tools
)未在modules.txt
中列出,但是,它们仍然可以通过vendor/
获得,因为在创建指向顶层目录的符号链接时,我们从所需模块开始传递遍历了所有go.mod
文件。这种模式的独特魅力在于,用户不必在
go.mod
文件中使用replace
指令,这意味着go.mod
可以保持相当通用,基本上只需要在build命令中添加-mod vendor
开关即可。