Wie werden GCC und g ++ gebootet?


185

Das nervt mich schon eine Weile. Wie kompilieren sich GCC und g ++?

Ich vermute, dass jede Revision mit einer zuvor erstellten Revision kompiliert wird. Ist das wahr? Und wenn ja, bedeutet dies, dass die ältesten g ++ - und GCC-Versionen in Assembly geschrieben wurden?


13
Jede Revision kann schließlich für sich zusammengestellt werden. :)
Martin Hennings

4
Dies ist interessant zu lesen, wenn Sie sehen möchten, wie die ersten Compiler entstanden sind.
Parkovski

1
@parkovski Ist der Link tot?
Nubcake

Antworten:


175

Die älteste Version von GCC wurde mit einem anderen C-Compiler kompiliert, da es beim Schreiben andere gab. Der allererste C-Compiler überhaupt (ca. 1973, IIRC) wurde entweder in der PDP-11- Assembly oder in der vorhergehenden B-Programmiersprache implementiert, aber auf jeden Fall wurde der B-Compiler in Assembly geschrieben.In ähnlicher Weise wurde der erste C ++ - Compiler (CPre / Cfront , 1979-1983) wahrscheinlich zuerst in C implementiert und dann in C ++ neu geschrieben.

Wenn Sie GCC oder einen anderen selbsthostenden Compiler kompilieren, lautet die vollständige Reihenfolge der Erstellung:

  1. Erstellen Sie eine neue Version von GCC mit dem vorhandenen C-Compiler
  2. Erstellen Sie eine neue Version von GCC mit der gerade erstellten Version neu
  3. (optional) Wiederholen Sie Schritt 2 zu Überprüfungszwecken.

Dieser Vorgang wird als Bootstrapping bezeichnet . Es testet die Fähigkeit des Compilers, sich selbst zu kompilieren, und stellt sicher, dass der resultierende Compiler mit allen Optimierungen erstellt wird, die er selbst implementiert.

EDIT : Drew Dormann verweist in den Kommentaren auf Bjarne Stroustrups Bericht über die früheste Implementierung von C ++ . Es wurde in C ++ implementiert, aber von Stroustrup als "Präprozessor" von C ++ nach C übersetzt. Nach seiner Definition kein vollständiger Compiler, aber dennoch wurde C ++ in C gebootet.


19
Die dreistufige Version des Bootstrap-Erstellungsprozesses dient in der Tat zur Überprüfung: Der Compiler selbst wird als eigener Testfall verwendet. GCC, das mit [other] kompiliert wurde, sollte dieselben Ergebnisse liefern (identische Binärdateien, wie Diskontierungsmakros wie __DATE__und __TIME__die sogar zwischen Aufrufen desselben Compilers variieren ) wie GCC, kompiliert mit [GCC kompiliert mit [other]] - wenn nicht, ist das ein Fehler, und Der 3-stufige Bootstrap-Build wurde entwickelt, um dies zu erfassen.
PMDJ

19
@pmjordan: "Wenn nicht, ist das ein Fehler" oder, weniger wahrscheinlich, eine hinterhältige Hintertür, die gerade eingeführt wird ("Reflections on Trusting Trust").
Steve Jessop

12
@sleske: das stimmt nicht. Die Binärausgabe von Schritt 2 muss mit der Binärausgabe von Schritt 3 identisch sein, andernfalls liegt irgendwo ein Fehler vor. Der Grund ist, wie pmjordan sagt: NewCompiler1 und NewCompiler2 sind Programme mit identischer Quelle (die von NewCompiler). Sie erhalten identische Eingaben (die Quelle für NewCompiler). Daher erzeugen sie identische Ausgaben, unabhängig davon, mit welchem ​​Compiler sie selbst kompiliert wurden (in diesem Fall wurde NewCompiler1 mit OldCompiler und NewCompiler2 mit NewCompiler1 kompiliert). Das heißt, NewCompiler2 und NewCompiler3 sind binär identisch.
Steve Jessop

12
Ich habe Sie sich jemals gefragt: Was wäre, wenn wir alle C-Compiler-Binärdateien verloren hätten? Und musste von Grund auf neu booten? So würde ich vorgehen: Es gibt den Tiny C Compiler (der tatsächlich den Linux-Kernel kompilieren kann, also ist die Funktion ziemlich vollständig). Alle C-Quelldateien enthalten lediglich 30.000 Codezeilen, einschließlich Kommentaren. Obwohl es eine ziemliche Anstrengung war, konnte jemand, der C versteht, aus den Quellen lernen, wie man eine binäre Ausgabe erzeugt und die TCC-Quellen aus der Hand "kompiliert" (ich denke hier tatsächlich an Lochkarten). Kompilieren Sie dann TCC damit neu und verwenden Sie es, um GCC oder ähnliches zu booten.
Datenwolf

11
@datenwolf: so ähnlich ja. Wenn wir davon ausgehen können, dass wir alle C-Compiler-Binärdateien verloren haben, aber noch einen Assembler haben, schreiben wir möglicherweise ein Assembler-Programm TinyTinyC. Es wäre ein C-Compiler mit weniger Funktionen als TinyC: Wir brauchen ihn nicht, um GCC oder den Linux-Kernel kompilieren zu können, wir brauchen ihn nur, um TinyC kompilieren zu können. Führen Sie es dann auf der Quelle von TinyC aus, die uns einen C-Compiler gibt, der Linux (und hoffentlich glibc und GCC) kompilieren kann, und wir sind im Geschäft. Wenn wir nicht einmal einen Assembler haben, dann booten wir zuerst einen davon, es ist einfacher als ein C-Compiler.
Steve Jessop
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.