Why Bootstrapping a Compiler From Scratch Is Harder Than It Looks

Building the Go toolchain from source starting with its last C-based version works well in theory, but hidden dependencies on operating systems and outside tools can break the chain in practice.

The Go compiler toolchain is written in Go, which raises a question for anyone who does not want to trust a pre-built binary. Early versions were written in C, so in principle you can build Go 1.4 with a C compiler and then use it to build each later release in turn. The Go documentation lists which versions can be built with which.

The first hidden dependency is long-term operating system compatibility. Go 1.4 built on a modern system produces a modern binary, but the binaries it creates for Go 1.19 are effectively frozen at the era of Go 1.4, with the system calls and ABIs of that time. Each step in the chain carries the same kind of frozen assumptions. Linux is very good at running decades-old binaries, so the chain works there. Other systems, such as OpenBSD, do not promise ABI compatibility between releases, and old Go binaries may not run on current versions.

The second dependency is on external programs the toolchain calls, such as the system linker, assembler or C compiler. Old toolchain versions pass the command line arguments that were valid when they were current, and those programs often do not treat their arguments as a stable interface.

As the Go documentation notes, the Go project has had to update the old Go 1.4 toolchain to keep it working on newer systems. The changes can be seen in the commit log of the Go 1.4 branch.

Source: Lobster


Posted

in

by

Tags: