Comment GCC et g ++ sont-ils amorcés?

186

Cela me dérange depuis un moment. Comment GCC et g ++ se compilent-ils?

Je suppose que chaque révision est compilée avec une révision précédemment construite. Est-ce vrai? Et si c'est le cas, cela signifie-t-il que les versions les plus anciennes de g ++ et GCC ont été écrites en assembly?

user1010005
la source
13
Chaque révision peut enfin être compilée par elle-même. :)
Martin Hennings
4
Ceci est intéressant à lire si vous voulez voir comment les premiers compilateurs sont nés.
parkovski
1
@parkovski Le lien est-il mort?
Nubcake
Lien vu pour la dernière fois le 04 juin 2016: web.archive.org/web/20160604035203/homepage.ntlworld.com/…
akraf

Réponses:

175

La version la plus ancienne de GCC a été compilée en utilisant un autre compilateur C, car il y en avait d'autres lors de son écriture. Le tout premier compilateur C (vers 1973, IIRC) a été implémenté soit dans l' assemblage PDP-11 , soit dans le langage de programmation B qui l'a précédé, mais dans tous les cas, le compilateur B a été écrit en assemblage.De même, le tout premier compilateur C ++ (CPre / Cfront , 1979-1983) a probablement été implémenté pour la première fois en C, puis réécrit en C ++.

Lorsque vous compilez GCC ou tout autre compilateur auto-hébergé, l'ordre complet de construction est:

  1. Construire une nouvelle version de GCC avec le compilateur C existant
  2. reconstruire une nouvelle version de GCC avec celle que vous venez de construire
  3. (facultatif) répétez l'étape 2 à des fins de vérification.

Ce processus est appelé bootstrap . Il teste la capacité du compilateur à se compiler et s'assure que le compilateur résultant est construit avec toutes les optimisations qu'il implémente lui-même.

EDIT : Drew Dormann, dans les commentaires, souligne le compte rendu de Bjarne Stroustrup de la première implémentation de C ++ . Il a été implémenté en C ++ mais traduit par ce que Stroustrup appelle un "préprocesseur" de C ++ vers C; pas un compilateur complet par sa définition, mais C ++ était quand même amorcé en C.

Fred Foo
la source
19
La version en 3 étapes du processus de construction de bootstrap est en effet pour vérification: le compilateur lui-même est utilisé comme son propre cas de test. GCC compilé avec [autre] devrait produire les mêmes résultats (binaires identiques, actualisant les macros comme __DATE__et __TIME__qui varient même entre les invocations du même compilateur) que GCC compilé avec [GCC compilé avec [autre]] - sinon, c'est un bogue, et la construction bootstrap en 3 étapes est conçue pour saisir cela.
pmdj
19
@pmjordan: "sinon, c'est un bug" ou, moins probable, une porte dérobée sournoise en cours d'introduction ("Reflections on Trusting Trust").
Steve Jessop
12
@sleske: ce n'est pas vrai. La sortie binaire de l'étape 2 doit être identique à la sortie binaire de l'étape 3, sinon il y a un bogue quelque part. La raison est comme le dit pmjordan: NewCompiler1 et NewCompiler2 sont des programmes avec une source identique (celle de NewCompiler). Ils reçoivent une entrée identique (la source de NewCompiler). Par conséquent, ils produiront une sortie identique quel que soit le compilateur avec lequel ils ont eux-mêmes été compilés (dans ce cas, NewCompiler1 a été compilé avec OldCompiler et NewCompiler2 a été compilé avec NewCompiler1). Autrement dit, NewCompiler2 et NewCompiler3 sont binaires identiques.
Steve Jessop
12
Je vous suis déjà demandé: et si nous perdions tous les binaires du compilateur C? Et dû démarrer à partir de zéro? Voici comment je procéderais: il y a le Tiny C Compiler (qui peut en fait compiler le noyau Linux, donc c'est assez complet). Tous ses fichiers source C ne font que 30k lignes de code, commentaires compris. Bien que même cela ait demandé un certain effort, quelqu'un qui comprend le C pourrait apprendre des sources, comment générer une sortie binaire et "compiler" les sources TCC à la main (je pense en fait aux cartes perforées ici). Puis recompilez TCC avec cela et utilisez-le pour amorcer GCC ou similaire.
datenwolf
11
@datenwolf: quelque chose comme ça, oui. Si nous pouvons supposer que nous avons perdu tous les binaires du compilateur C, mais que nous avons toujours un assembleur, alors nous pourrions écrire un programme assembleur TinyTinyC. Ce serait un compilateur C moins complet que TinyC: nous n'en avons pas besoin pour pouvoir compiler GCC ou le noyau Linux, nous en avons seulement besoin pour compiler TinyC. Ensuite, exécutez-le sur le source de TinyC, cela nous donne un compilateur C capable de compiler Linux (et espérons-le glibc et GCC) et nous sommes en affaires. Si nous n'avons même pas d'assembleur, alors nous commencerions par en amorcer un, c'est plus facile qu'un compilateur C.
Steve Jessop