直接 go build 源码树会失败,因为 go 编译器自举存在循环依赖,需通过 make.bash/make.bat 分三阶段构建,且依赖 goroot_bootstrap 指向有效的 go 1.17+ 安装。

为什么直接 go build 源码树会失败
Go 的编译器(cmd/compile)本身是用 Go 写的,但构建它需要一个能运行的 Go 工具链——这形成循环依赖。源码树里没有预编译的 compiler 可执行文件,go build ./src/cmd/compile 会报错:cannot find package "unsafe" 或直接卡在 runtime 初始化失败。
- Go 构建系统默认跳过
src/下的自举逻辑,不识别make.bash之外的入口 -
go build依赖已安装的GOROOT和GOBIN,而源码树尚未“成为”合法GOROOT - 部分包(如
runtime、reflect)含汇编或引导专用符号,普通构建无法解析
必须用 make.bash(或 make.bat)启动自举
Go 官方只支持通过顶层脚本触发完整自举流程,它会分三阶段:用系统已有 Go 编译出引导工具 → 用引导工具编译第一版 stdlib → 用新 stdlib 重新编译全部命令和运行时。这个过程绕过了 go build 的路径与依赖检查。
- Linux/macOS 下运行:
./src/make.bash(不是make命令,也不是bash make.bash) - Windows 下运行:
src\make.bat(需在 cmd.exe 中,PowerShell 不兼容) - 执行前确保
$GOROOT_BOOTSTRAP指向一个可用的 Go 1.17+ 安装(不能是正在构建的源码目录) - 脚本会把结果输出到
./go/目录,不是系统$GOROOT,避免污染现有环境
GOROOT_BOOTSTRAP 设错会导致静默失败
如果 GOROOT_BOOTSTRAP 指向一个太老(如 Go 1.10)、损坏或权限不足的 Go 安装,make.bash 可能中途退出却不报错,最终 ./go/bin/go 文件存在但无法运行,执行时报 panic: runtime error: invalid memory address 或直接段错误。
- 验证方式:
$GOROOT_BOOTSTRAP/bin/go version必须输出有效版本,且该 Go 能成功go build hello.go - 常见坑:用 Homebrew 安装的 Go 有时
bin/权限受限;Docker 容器中未挂载/usr/local/go导致路径失效 - Mac M1/M2 用户注意:
GOROOT_BOOTSTRAP必须与目标架构一致(ARM64 Go 不能引导 amd64 Go)
自举后生成的 ./go 目录不能直接当 GOROOT
新构建的 Go 工具链默认不包含 pkg/mod 和 pkg/sumdb,且 go env GOROOT 会返回空或错误路径,导致 go mod 等命令异常。这不是 bug,而是自举产物的设计限制。
- 正确做法:将
./go整个目录复制到安全位置(如/opt/go-custom),再设置GOROOT=/opt/go-custom - 别直接软链接
./go到/usr/local/go——后续再次运行make.bash会覆盖,引发不可逆损坏 - 若需调试运行时,记得加
CGO_ENABLED=1,否则runtime/pprof等依赖 C 的功能会禁用
自举不是一次性的配置活,每次改 src/runtime 或 src/cmd/compile/internal 都得重跑 make.bash;中间任何一步中断,就得删掉 ./go 从头来——没缓存,也没增量编译。










