作者解释编译器自举为什么依赖的东西比想象中多。Go 工具链用 Go 写成,但早期版本用 C 写成,理论上可以从最后一个 C 版本出发自举起当前的 Go 编译器,官方文档也列出了哪个版本能构建哪个版本。但这只在部分平台可行,因为存在两个隐藏依赖。其一是操作系统对「旧」二进制的长期兼容性:用现代 C 编译器构建出的 Go 1.4 会调用现代的 C 标准库与系统调用,而它构建出的 Go 1.19 实际上冻结在 Go 1.4 时期的 ABI 上,之后依此类推。Linux 内核对几十年前的旧二进制极其宽容,所以链能走通;OpenBSD 不保证跨版本 ABI 兼容,这条链就很难走。其二是工具链用到外部程序时,依赖的是当年那套命令行参数,而这些程序通常不把参数当需要长期保持稳定的 API。
🔑 核心要点
理论路径:Go 工具链早期版本用 C 写成,因此可以从最后一个 C 版本开始自举,文档给出了版本对应关系
第一个隐藏依赖:操作系统对「旧」二进制的长期兼容性,用 Go 1.4 构建出的 Go 1.19 冻结在 Go 1.4 时代的 ABI 上
Linux 内核对几十年前的旧二进制依然宽容,所以这条自举链能走通
OpenBSD 不保证跨版本 ABI 兼容,历史上还做过影响 Go 的改动,从零自举会很麻烦
第二个隐藏依赖:工具链若调用系统链接器、汇编器或 C 编译器,就依赖它们当年的命令行参数
这些外部程序通常不把命令行参数当作需要长期保持稳定的 API;Go 实际上也不得不回头修改 Go 1.4 工具链
💡 金句
并非所有语言工具链都像 Go 那样自成一体,使用系统汇编器或链接器完全合理,但这会让你依赖它们的命令行参数与工作方式。