如何让 Go 在 aarch64 Linux 构建时不使用 gold linker?
可以在 go build 中通过 -ldflags 向外部链接驱动传入 -extldflags=-fuse-ld=bfd,尝试改用 GNU BFD linker。前提是 CI 的 SDK 内已提供支持目标架构的 ld.bfd,且其版本适用于当前构建。
如何指定其他链接器
在原来的构建命令中加入相应参数:
go build -ldflags='-extldflags=-fuse-ld=bfd' .
示例中的 . 表示当前目录的包。实际使用时,保留原命令中的包路径、build tags 和其他必要参数。如果已经设置了 -ldflags,将新参数合并到原有值中。
参数分为两层:-ldflags 将参数交给 Go linker,-extldflags 再将参数交给外部链接驱动。两者的用途可参见 Go linker 文档。-fuse-ld=bfd 是 GCC 选择 BFD linker 的选项,详见 GCC 链接选项。
无需直接将 -extld 设为 ld.bfd。日志中的外部链接驱动是 gcc,它负责组织底层链接器的调用。通常保留这个驱动,用 -fuse-ld 选择链接器即可。
为什么会出现 gold
日志显示,失败发生在 Go linker 调用 gcc 完成外部链接的阶段。cannot find ‘ld’ 与链接器缺失或查找路径异常相符,但仅凭这段日志无法确认 SDK 中安装了哪些链接器。
Go 在 Linux/ARM64 的部分动态链接路径中会选择 gold,以规避旧 GNU ld 在 COPY relocation 和 -z nocopyreloc 上的问题。选择逻辑因 Go 版本而异:当前源码会检查默认 GNU ld 的版本,对 2.35 及更早版本选择 gold。因此,不能仅凭架构判断必须使用 gold,更换链接器时也需要考虑其版本。Go 外部链接实现
先检查 CI 内的工具链
在实际运行构建的 SDK 环境中执行:
go version
go env GOOS GOARCH CGO_ENABLED CC GOFLAGS
command -v ld.bfd
ld.bfd --version
如果找不到 ld.bfd,需要先让 Flathub 使用的 SDK 提供对应工具链。宿主机安装了链接器,CI 的 SDK 内也未必能访问。使用交叉工具链时,还应检查目标架构对应的链接器,不能只检查未带前缀的 ld.bfd。
怎样确认覆盖参数生效
构建时可以同时打开 Go 构建日志和 linker 的详细日志:
go build -x -ldflags='-v -extldflags=-fuse-ld=bfd' .
检查最终的 gcc 调用是否收到 -fuse-ld=bfd。Go 生成的命令中可能仍保留前面的 -fuse-ld=gold,而用户传入的 -extldflags 会追加在后面。需要结合参数顺序和实际执行结果判断。Go 外部链接参数处理
如果仍然提示找不到链接器,继续检查 GCC 的搜索路径及 SDK 安装情况。如果改为报告 relocation 错误,则需要重新评估 BFD linker 的版本和兼容性。
部分旧工具链还可能在正式链接前检查 gold。如果直接出现要求安装 gold 的检查错误,仅追加 -extldflags 可能无法绕过。此时应更新 SDK 中的 Go 和 Binutils,或补齐该工具链要求的 gold。原始材料没有给出 Go、GCC 和 Binutils 版本,无法断言上述命令在该 CI 环境中一定成功。
备注:内容仅供参考。
