No posts yet. Check back soon!
Compiler bootstrapping depends on more than you might think
02:24 AM · Oct 10, 2026
Like many languages and their toolchains, the Go compiler toolchain is written in Go. This presents a little bit of a problem if you want to wind up with a Go compiler without having to trust someone else's pre-built binary of it. Fortunately, the early versions of the Go toolchain were written in C, which (in theory) allows us to bootstrap a current binary of the Go compiler starting from the last version written in C. The Installing Go from source documentation has a list of what versions of Go can be built with what (which gets increasingly fine-grained with recent Go releases).
Well, that's the theory. In practice this is only going to work on some platforms, such as x86 Linux, because there's a hidden dependency or two in this sequence of bootstrapping. The big hidden dependency is long term operating system compatibility with 'old' binaries. When you build Go 1.4 with your modern C compiler and OS, you will get a modern binary that calls your modern C standard library and kernel system calls in the appropriate way. But when you use your newly built Go 1.4 to build Go 1.19, the Go binary it produces is one that was effectively frozen around the time Go 1.4 was released; it makes the system calls and expects the ABIs and so on that were current then, not that are current now. Then the binary of Go 1.21 that your Go 1.19 toolchain produces will similarly be frozen at the state of ABIs as of Go 1.19, and so on.
The Linux kernel is extremely good about backwards compatibility with old binaries; binaries that are literally decades old can and will still run happily. On Linux, you can expect this sequence of 'new old stock' Go toolchain binaries to work without problems. But not all operating systems consider binary backward compatibility to be critical, or even deeply important. For example, OpenBSD doesn't guarantee it will maintain ABI compatibility between releases (cf) and in the past it's made changes that mattered for Go. I wouldn't be surprised if older versions of the Go toolchain produce binaries that won't run on the current version of OpenBSD, which would obviously complicate a from-scratch bootstrapping of Go on OpenBSD.
The other hidden dependency is on how any outside programs used by the toolchain work, for example what specific arguments they accept or require. If your language's toolchain at some point uses the standard system linker, assembler, C compiler, or whatever, it depends on being able to pass them the right arguments and in general for them to operate the way it expects. Old versions of your toolchain will be using the command line arguments for outside programs that were current when those old toolchains were supported, not the ones you may need today, possibly years after the fact. Not all language toolchains are self-contained the way Go (mostly) is; it's perfectly reasonable to use the system assembler or linker or whatever rather than write your own (in addition to your actual compiler system). But this leaves you depending on their command line arguments and how they work, and often the programs don't consider that sort of thing a stable API that has to be preserved over the long term.
(As covered in the Go documentation, Go has actually had to update the old 'Go 1.4' toolchain in order to keep it working on more modern systems. You can get an idea of the changes necessary by looking at the Go 1.4 branch's commit log.)