tools.go 是 Go 官方推荐的隔离开发工具依赖的约定文件,非必需但用于声明 gopls、air 等 dev 工具;它通过 // +build tools 构建约束被 go mod tidy 忽略,避免污染运行时依赖,需严格满足文件名、包名和注释三条件。

tools.go 是什么,为什么不能用 go.mod 直接装 dev 依赖
它不是“必须存在”的文件,而是 Go 官方推荐的一种隔离开发工具依赖的约定。因为 go.mod 只管理运行时依赖,而 golang.org/x/tools/cmd/gopls、github.com/cosmtrek/air 这类工具一旦写进 go.mod,就会被 go list -deps 扫到、影响构建分析,甚至意外被 go build 尝试编译——尤其当它们含 main 包时,会报 cannot load main module 错误。
tools.go 的本质:一个空的、带 // +build tools 构建约束的 Go 文件,只声明 import,不执行任何逻辑。Go 工具链(如 go mod tidy)默认忽略它,但人和 IDE 能一眼看出“这些是工具”。
怎么写一个合规的 tools.go
必须满足三个条件,缺一不可:
- 文件名严格为
tools.go(小写,无下划线、无版本号) - 包声明为
package tools(不能是main或其他) - 顶部有构建约束注释
// +build tools,且下一行必须是空行
示例:
立即学习“go语言免费学习笔记(深入)”;
// +build tools package tools import ( _ "golang.org/x/tools/cmd/gopls" _ "github.com/cosmtrek/air" _ "github.com/go-delve/delve/cmd/dlv" )
注意:_ 导入是必须的——不用 var _ = ... 或实际调用,否则 go mod tidy 会把它从 go.mod 清掉。
go mod tidy 为什么没把工具加进 go.mod
这是正常现象,不是 bug。因为 go mod tidy 默认只处理当前构建上下文可见的依赖,而 // +build tools 让这个文件在常规构建中被跳过。
要让它生效,得显式告诉 Go:“这次请把 tools 构建标签也带上”:
- 运行
go mod tidy -v看日志,确认它是否扫描了tools.go - 手动触发:先
GOOS= GOARCH= go build -tags tools ./...(空环境变量避免平台干扰),再跑go mod tidy - 更稳妥:用
go install直接装,比如go install golang.org/x/tools/cmd/gopls@latest,绕过go.mod管理
常见坑:go mod tidy 后 go.mod 没变化,就以为失败了——其实它只是没动,工具仍可正常使用;真正要检查的是 go list -f '{{.Dir}}' -tags tools golang.org/x/tools/cmd/gopls 是否能定位到本地缓存路径。
vscode-go / gopls 读不到 tools.go 里的工具怎么办
gopls 默认不解析 tools.go,它依赖 go.mod 或 go.work 中显式声明的依赖。所以即使 tools.go 写对了,VS Code 仍可能提示 “gopls not found”。
解决方式分两层:
- 确保
gopls已安装到$GOPATH/bin或$GOBIN:运行go install golang.org/x/tools/cmd/gopls@latest - 在 VS Code 的
settings.json中指定路径:"go.goplsPath": "/path/to/gopls",或留空让其自动发现 - 如果项目用了 Go Workspace(
go.work),需把工具模块也加进use列表,否则 gopls 启动时加载的模块范围不含它们
容易被忽略的一点:某些 CI 环境或容器镜像里,GOBIN 未设或 $PATH 没包含它,导致 gopls 装了却找不到——这时别改 tools.go,先查 which gopls 和 echo $GOBIN。










