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 将创建一个作用域,并将 GOOSGOARCH 设置为与文件匹配的值。

例如,假设我们有一个包含三个模块的存储库:modamodbmodc,以及一个使用模块 modamodbgo.work 文件。如果我们打开文件 moda/a.gomodb/b.gomoda/a_windows.gomodc/c.go,gopls 将自动创建三个构建。

Zero Config 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/goplsgolang.org/x/mod

cd $WORK
go work init
go work use tools/gopls mod

然后,在您的编辑器中打开 $WORK 目录。

何时手动配置 GOOSGOARCH-tags

如第一节所述,gopls v0.15.0 及更高版本将在您打开与系统默认操作系统 (GOOS) 或架构 (GOARCH) 不匹配的文件时,尝试自动配置新的构建范围。

但是,根据该节中列出的注意事项,此自动行为存在局限性。通过在您的 "build.env" 中设置 GOOSGOARCH,或在您的 “build.buildFlags” 中设置 -tags=... 来自定义您的 gopls 环境,当

  • 您想修改默认构建环境。
  • Gopls 无法猜测您希望用于跨平台开发的 GOOS/GOARCH 组合。
  • 您需要处理一个受用户定义的构建标签约束的文件,例如 //go:build mytag 指令。

GOPATH 模式

当打开 GOPATH 目录中的目录时,工作区范围将仅限于该目录及其包含的所有目录。请注意,打开一个大的 GOPATH 目录可能会导致 gopls 启动非常缓慢。


本文档的源代码可以在 golang.org/x/tools/gopls/doc 下找到。