Gopls:设置您的工作区
在语言服务器协议中,“工作区”由一个文件夹以及每个文件夹的配置组成。一些 LSP 客户端(如 VS Code)允许显式配置工作区,而另一些客户端则通过查找定义工作区根目录的特殊文件(例如 .git
目录或 go.mod
文件)来自动进行配置。
为了正常工作,gopls 需要一个定义好的范围,在该范围内应执行诸如引用、重命名和实现等语言功能。换句话说,gopls 需要从 LSP 工作区推断出您将用于构建工作区的 go build
调用,包括工作目录、环境和构建标志。
过去,设置工作区以使 gopls 推断出正确的构建信息可能很棘手。这需要打开正确的目录或使用 go.work
文件告知 gopls 您正在处理的模块,并提前配置正确的操作系统和架构。当这未能如预期工作时,gopls 经常会以神秘的方式失败——可怕的“未找到包”错误。
从 gopls v0.15.0 开始,工作区配置变得更加简单,当您在工作区中的任何位置打开 Go 文件时,gopls 通常都可以正常工作。如果它对您不起作用,或者您想更好地了解 gopls 如何建模您的工作区,请继续阅读。
工作区构建
从 gopls v0.15.0 开始,gopls 将根据打开的文件集猜测您正在处理的构建。当您在工作区文件夹中打开一个文件时,gopls 会检查该文件是否包含在模块、go.work
工作区或 GOPATH 目录中,并相应地配置构建。此外,如果您打开一个受限于不同操作系统或架构的文件(例如,在 Linux 上工作时打开 foo_windows.go
),gopls 将创建一个作用域,并将 GOOS
和 GOARCH
设置为与文件匹配的值。
例如,假设我们有一个包含三个模块的存储库:moda
、modb
和 modc
,以及一个使用模块 moda
和 modb
的 go.work
文件。如果我们打开文件 moda/a.go
、modb/b.go
、moda/a_windows.go
和 modc/c.go
,gopls 将自动创建三个构建。
这使得 gopls 在您打开 Go 文件时能够“即插即用”,但这也带来了一些需要注意的事项:
- 这会导致 gopls 进行更多工作,因为它现在需要跟踪三个构建而不是一个。但是,最近的 可伸缩性重新设计 通过高效的缓存可以避免其中的许多工作。
- 对于从给定文件调用的操作,例如“引用”或“实现”,gopls 会在该文件的默认构建中执行该操作。例如,从
foo_linux.go
查找符号S
的引用将返回来自 Linux 构建的引用,而从foo_windows.go
查找同一符号S
的引用将返回来自 Windows 构建的引用。Gopls 会搜索该文件的默认构建,但不会搜索所有其他可能的构建(尽管那样会很好),因为这可能会非常耗时。问题 #65757 和 #65755 提出了对此行为的改进。 - 在选择
GOOS/GOARCH
组合以匹配受构建约束的文件时,gopls 将从 此列表 中选择第一个匹配的组合。在某些情况下,这可能会令人惊讶。 - 当在与您的默认工具链不匹配的
GOOS/GOARCH
受约束的文件中工作时,将隐式设置CGO_ENABLED=0
,因为不太可能为该目标提供 C 工具链。这意味着 gopls 将无法处理包含import "C"
的文件。问题 #65758 可能会对此行为进行改进。 - Gopls 目前无法猜测包含任意用户定义构建约束的构建标志,例如带有
//go:build mytag
指令的文件。问题 #65089 提出了一个 gopls 可以自动处理此问题的启发式方法。
请通过点赞或评论上述问题,或就您希望看到的其他改进 提出新问题 来提供关于此行为的反馈。
何时使用 go.work
文件进行开发
从 Go 1.18 开始,go
命令内置支持由 go.work
文件指定的多个模块的工作区。如果 go.work
文件存在于您的工作区中,Gopls 将会识别它们。
当您需要以下情况时,请使用 go.work
文件:
- 您想在单个逻辑构建中同时处理多个模块,例如,您希望一个模块的更改反映在另一个模块中。
- 您想通过减少 gopls 必须跟踪的构建数量来提高 gopls 的内存使用量或性能。
- 您希望 gopls 在多模块工作区中知道您正在处理哪些模块,而无需打开任何文件。例如,在打开任何文件之前使用
workspace/symbol
查询可能很方便。 - 您正在使用 gopls v0.14.2 或更早版本,并且想处理多个模块。
例如,假设此存储库已检出到 $WORK/tools
目录,而 x/mod
已检出到 $WORK/mod
,并且您正在处理一个用于编辑 go.mod
文件的新 x/mod
API,您想同时将其集成到 gopls 中。
您可以通过创建 go.work
文件来同时处理 golang.org/x/tools/gopls
和 golang.org/x/mod
。
cd $WORK
go work init
go work use tools/gopls mod
然后,在您的编辑器中打开 $WORK
目录。
何时手动配置 GOOS
、GOARCH
或 -tags
如第一节所述,gopls v0.15.0 及更高版本将在您打开与系统默认操作系统 (GOOS
) 或架构 (GOARCH
) 不匹配的文件时,尝试自动配置新的构建范围。
但是,根据该节中列出的注意事项,此自动行为存在局限性。通过在您的 "build.env"
中设置 GOOS
或 GOARCH
,或在您的 “build.buildFlags” 中设置 -tags=...
来自定义您的 gopls 环境,当
- 您想修改默认构建环境。
- Gopls 无法猜测您希望用于跨平台开发的
GOOS/GOARCH
组合。 - 您需要处理一个受用户定义的构建标签约束的文件,例如
//go:build mytag
指令。
GOPATH 模式
当打开 GOPATH
目录中的目录时,工作区范围将仅限于该目录及其包含的所有目录。请注意,打开一个大的 GOPATH 目录可能会导致 gopls 启动非常缓慢。
本文档的源代码可以在 golang.org/x/tools/gopls/doc 下找到。