Go Wiki:GOPATH
GOPATH 变量
使用超出标准库的依赖项进行 Go 开发是 使用 Go 模块 完成的。使用 Go 模块时,GOPATH 变量(在 Unix 上默认为 $HOME/go
,在 Windows 上默认为 %USERPROFILE%\go
)用于以下目的
go install
命令将二进制文件安装到$GOBIN
,其默认为$GOPATH/bin
。go get
命令将下载的模块缓存到$GOMODCACHE
,其默认为$GOPATH/pkg/mod
。go get
命令将下载的校验和数据库状态缓存到$GOPATH/pkg/sumdb
。
有关 GOPATH 变量的完整详细信息,请参阅 go 命令文档。本页的其余部分涉及现已弃用的 GOPATH 开发模式。
GOPATH 开发模式
在 Go 模块之前,使用依赖项进行 Go 开发使用“GOPATH 开发模式”或简称“GOPATH 模式”。在 GOPATH 模式下,go
命令将 GOPATH 变量用于以下目的
go install
命令将二进制文件安装到$GOBIN
,其默认为$GOPATH/bin
。go install
命令将import "example.com/y/z"
的已编译软件包文件安装到$GOPATH/pkg/example.com/y/z.a
。go get
命令下载满足import "example.com/y/z"
的源代码到$GOPATH/src/example.com/y/z
。
弃用并移除 GOPATH 开发模式
Go 模块是 GOPATH 开发模式的替代品,旨在为整个 Go 生态系统添加包版本的概念。
从 GOPATH 开发模式到 Go 模块的过渡是渐进的,分布在许多 Go 版本中
-
Go 1.11(2018 年 8 月)引入了
GO111MODULE
变量,其默认值为auto
。使用GO111MODULE=off
时,go
命令始终使用 GOPATH 模式。使用GO111MODULE=on
时,go
命令始终使用模块模式。使用GO111MODULE=auto
(或不设置GO111MODULE
),go
命令根据当前目录决定模式。如果当前目录不在$GOPATH/src
中,并且位于根目录中带有go.mod
文件的源树中,则go
命令使用 Go 模块模式。否则,go
命令使用 GOPATH 模式。此规则确保在auto
模式下运行的所有命令在$GOPATH/src
中不受影响,但允许用户在其他目录中试验模块。 -
Go 1.13(2019 年 8 月)调整了
GO111MODULE=auto
模式以移除$GOPATH/src
限制:如果$GOPATH/src
中的目录有go.mod
文件,则在该目录或其子目录中运行的命令现在使用模块模式。这允许用户继续以基于导入的层次结构组织其签出的代码,但对单个签出使用模块。 -
Go 1.16(2021 年 2 月)将默认值更改为
GO111MODULE=on
,始终使用模块模式。也就是说,GOPATH 模式在默认情况下将被完全禁用。需要在另一个版本中使用 GOPATH 模式的用户可以明确设置GO111MODULE=auto
或GO111MODULE=off
。 -
Go 1.NN(???)将移除
GO111MODULE
设置和 GOPATH 模式,始终使用模块模式。
请注意,移除 GOPATH 开发模式并不意味着移除 GOPATH 变量。它仍将用于本页顶部列出的目的。
常见问题解答
GOPATH 变量是否会被移除?
否。GOPATH 变量(在环境中设置或通过 go env -w
设置)不会被移除。它仍将用于确定默认二进制安装位置、模块缓存位置和校验和数据库缓存位置,如本页顶部所述。
我是否仍可以在 GOPATH/src/import/path 中编写代码?
可以。许多 Go 开发人员欣赏此约定提供的结构,并将其模块存储库签出到其中。开始使用模块所需的所有代码都是一个 go.mod
文件。请参阅 go mod init
。
如何在 GOPATH/src 中编译一个仓库以针对另一个仓库中所做的更改?
如果要在构建另一个模块时使用一个模块中的未发布更改,可以向另一个模块的 go.mod
添加 replace
行。
例如,如果你已将 golang.org/x/website
和 golang.org/x/tools
检出到 $GOPATH/src/golang.org/x/website
和 $GOPATH/src/golang.org/x/tools
,那么要让 website
的本地构建自动使用 tools
中的更改,你需要将以下内容添加到 $GOPATH/src/golang.org/x/website/go.mod
replace golang.org/x/tools => ../tools
当然,replace
指令不了解 $GOPATH
。如果你已将这两个检出到 $HOME/mycode/website
和 $HOME/mycode/tools
,则同一行也会正常工作。
为什么移除 GOPATH 开发模式?
从本质上讲,GOPATH 开发模式基本上自动提供所有这些类型的 replace
行,以便你为依赖项构建的代码是你碰巧在计算机上检出的代码。这意味着你的构建会受到你碰巧保留的旧检出内容的影响,而你可能已经忘记了这些内容。这意味着你在一台机器上获得的构建可能与另一台机器不同,即使从同一顶级仓库的同一版本开始。而且,这意味着你获得的构建可能与同一项目中另一位开发人员获得的构建不同。Go 模块解决了所有这些可重复性问题。所有这些问题的根本原因是 GOPATH 模式没有任何包版本的概念。
除了可重复性之外,Go 模块还提供了一种处理代理和安全下载的清晰方式。当你 git clone
一个项目然后获取其依赖项时,这些依赖项会经过加密检查(使用 go.sum
文件)以确保它们与原始开发人员使用的位相同。唯一可信的部分是顶级 git clone
。这里同样如此,这只有在 Go 模块(与 GOPATH 模式相反)具有包版本的概念时才有可能。
对于 Go 自身的未来演进,模块明确标记了文件树的特定版本是用哪个版本的 Go 语言编写的。这使得在 Go 的更高版本中禁用有问题的特性(例如 string(1)
,许多人认为它生成 "1"
但实际上生成 "\x01"
(Ctrl-A))成为可能,同时保持旧程序的构建(因为它们明确标记为已针对旧版本的 Go 编写)。
还有更多类似的示例。
在 GOPATH 开发模式中,所有这些都是不可能的,因为该模式目前存在。在不弃用 GOPATH 模式的情况下,我们无法推进生态系统的发展,也无法真正开始依赖 Go 模块的这些重要特性。
(你可能还会问:为什么不直接将这些内容添加到 GOPATH 模式中?答案是:我们已经这么做了,结果就是 Go 模块。)
何时决定弃用 GOPATH 开发模式?
最初的计划是在 Go 1.13 中弃用 GOPATH 模式,但我们希望花更多时间让尽可能多的 Go 用户的模块更健壮,因此弃用从该版本中推迟。关于问题 #41330和 golang-tools 组的讨论没有发现任何弃用 GOPATH 的剩余障碍,因此现在已将其安排在 Go 1.16 中,并将在未来的版本中删除,如上文时间表中所述。
如果我还有更多关于从 GOPATH 开发模式迁移到 Go 模块的问题,该怎么办?
请参阅golang.org/help以获取资源列表。如果这些都不合适,请随时在此提交问题。我们希望每个人都能成功采用 Go 模块。
此内容是Go Wiki的一部分。