Ablaufskizze des Bootstrapping in drei Stufen: Links ein einfacher Startcompiler in C geschrieben (Stage 0), der den Quelltext des neuen Compilers übersetzt. In der Mitte das Ergebnis, ein erster lauffähiger Compiler der neuen Sprache (Stage 1). Rechts übersetzt dieser erneut denselben Quelltext und erzeugt Stage 2, den fertigen selbsttragenden Compiler. Ein durchgestrichener Pfeil zeigt, dass der Startcompiler danach entfällt.

Bootstrapping-Compiler

Ein Bootstrapping-Compiler ist ein Übersetzungsprogramm für eine Programmiersprache, das selbst in genau dieser Sprache geschrieben ist. Damit ein solcher Compiler überhaupt entstehen kann, braucht es eine erste, einfache Version, die in einer anderen Sprache gebaut wurde.

Programme werden von Menschen in einer gut lesbaren Programmiersprache geschrieben. Ein Prozessor versteht davon nichts, er kennt nur Maschinenbefehle aus Nullen und Einsen. Ein Compiler ist ein Programm, das diese Übersetzung erledigt. Er selbst ist aber auch nur ein Programm und muss deshalb ebenfalls in irgendeiner Sprache geschrieben sein. Von Bootstrapping spricht man, wenn der Compiler für eine Sprache in genau dieser Sprache geschrieben ist. Der Compiler übersetzt also sich selbst — und das klingt zunächst nach einem unmöglichen Kreis.

Warum sich Sprachen selbst übersetzen wollen

Der wichtigste Grund ist ein Praxistest. Wer eine neue Programmiersprache entwirft, will wissen, ob sie für große, ernsthafte Software taugt. Ein Compiler ist genau so ein Programm: umfangreich, komplex und unbarmherzig gegenüber schlechten Entwürfen. Wenn eine Sprache nicht einmal gut genug ist, um ihren eigenen Compiler zu schreiben, ist das ein schlechtes Zeichen.

Dazu kommt ein sehr praktischer Punkt. Die Entwickler eines Compilers sind gleichzeitig seine intensivsten Nutzer. Jede Schwäche der Sprache spüren sie täglich am eigenen Projekt. Fehler und umständliche Konstruktionen fallen dadurch schnell auf und werden schnell behoben. Man nennt dieses Prinzip auch, sein eigenes Hundefutter zu essen.

Schließlich macht Bootstrapping das Projekt unabhängig. Ein Compiler, der dauerhaft eine fremde Sprache braucht, hängt an deren Werkzeugen und deren Fortbestand. Wer sich selbst übersetzt, braucht am Ende nur noch sich selbst. Sprachen wie Go, Rust und C haben genau diesen Weg genommen.

Der Weg aus dem Henne-Ei-Problem

Der scheinbare Kreis lässt sich mit einem Trick aufbrechen. Zuerst schreibt man einen kleinen, einfachen Compiler in einer bereits vorhandenen Sprache, oft in C. Dieser erste Compiler ist unschön und kann nur einen Teil der neuen Sprache. Er reicht aber aus, um eine erste Version des richtigen Compilers zu übersetzen. Diesen Starthelfer nennt man Stage 0 oder Startcompiler.

Danach folgt der eigentliche Schritt. Der vollständige Compiler wird in der neuen Sprache selbst geschrieben. Der Startcompiler übersetzt diesen Quelltext in ein lauffähiges Programm. Jetzt existiert erstmals ein Compiler der neuen Sprache, der in der neuen Sprache geschrieben ist. Von hier an wird der Startcompiler nicht mehr gebraucht und kann weggeworfen werden.

Ein Vergleich hilft: Um eine Werkstatt einzurichten, braucht man Werkzeug. Also leiht man sich zuerst fremdes Werkzeug aus. Damit fertigt man eigene, bessere Werkzeuge an. Anschließend gibt man das geliehene zurück und arbeitet nur noch mit den eigenen. Genau so verhält es sich beim Bootstrapping. Ab dann läuft die Weiterentwicklung in Stufen: Version 5 des Compilers wird mit Version 4 übersetzt, Version 6 mit Version 5, und so weiter.

Vom Linux-Kernel bis zum Vertrauensproblem

Sichtbar wird das Thema vor allem bei der Installation von Software aus dem Quelltext. Wer eine Linux-Distribution von Grund auf baut, stößt fast sofort auf die Bootstrap-Kette des C-Compilers GCC. Auch der Rust-Compiler lädt beim Bauen zunächst eine ältere, fertige Version von sich selbst herunter. Große Sprachen bringen ihre eigene Startgeschichte mit.

In Sicherheitsdiskussionen taucht Bootstrapping regelmäßig als Risiko auf. Der Informatiker Ken Thompson beschrieb 1984 einen berühmten Angriff. Ein manipulierter Compiler kann Schadcode in Programme einbauen, ohne dass im Quelltext etwas davon steht. Weil er sich selbst übersetzt, gibt er die Manipulation an alle Folgeversionen weiter. Der Quelltext sieht dabei völlig sauber aus.

Deshalb gibt es heute Projekte, die die gesamte Kette nachvollziehbar machen wollen. Sie beginnen bei einem winzigen, von Hand prüfbaren Programm und bauen daraus Schritt für Schritt moderne Compiler auf. Reproducible Builds ist das Stichwort, das dazu in Fachnachrichten fällt. Ein verwandter, aber anderer Begriff ist der Interpreter: Er führt Programme direkt aus, statt sie vorher komplett zu übersetzen.

Subscribe free. Unsubscribe the second it sucks.

High-signal news across AI, business, UX, and tech. Every morning.