Como o GCC e o g ++ são inicializados?

186

Isso tem me incomodado por algum tempo. Como o GCC e o g ++ se compilam?

Estou supondo que toda revisão seja compilada com uma revisão criada anteriormente. Isso é verdade? E se for, isso significa que as versões mais antigas do g ++ e do GCC foram gravadas em assembly?

user1010005
fonte
13
Cada revisão pode finalmente ser compilada sozinha. :)
Martin Hennings
4
Isso é interessante para ler se você quiser ver como os primeiros compiladores surgiu.
parkovski
1
@parkovski O link está morto?
Nubcake
Última vez que o link foi visto em 04 de junho de 2016: web.archive.org/web/20160604035203/homepage.ntlworld.com/…
akraf 03/12/19

Respostas:

175

A versão mais antiga do GCC foi compilada usando outro compilador C, pois havia outras quando ele foi gravado. O primeiro compilador C de todos os tempos (ca. 1973, IIRC) foi implementado no assembly PDP-11 ou na linguagem de programação B que o precedeu, mas, em qualquer caso, o compilador B foi escrito em assembly.Da mesma forma, o primeiro compilador C ++ (CPre / Cfront , 1979-1983) provavelmente foi implementado primeiro em C, depois reescrito em C ++.

Quando você compila o GCC ou qualquer outro compilador de hospedagem automática, a ordem completa de criação é:

  1. Crie uma nova versão do GCC com o compilador C existente
  2. recrie a nova versão do GCC com a que você acabou de criar
  3. (opcional) repita a etapa 2 para fins de verificação.

Esse processo é chamado de inicialização . Ele testa a capacidade do compilador de se compilar e garante que o compilador resultante seja construído com todas as otimizações que ele próprio implementa.

Edição : Drew Dormann, nos comentários, aponta para o relato de Bjarne Stroustrup sobre a implementação mais antiga do C ++ . Foi implementado em C ++, mas traduzido pelo que Stroustrup chama de "pré-processador" de C ++ para C; não é um compilador completo por sua definição, mas ainda assim o C ++ foi inicializado em C.

Fred Foo
fonte
19
A versão em três etapas do processo de construção do bootstrap é realmente para verificação: o próprio compilador é usado como seu próprio caso de teste. O GCC compilado com [other] deve produzir os mesmos resultados (binários idênticos, descontando macros como __DATE__e __TIME__que variam mesmo entre invocações do mesmo compilador) que o GCC compilado com [GCC compilado com [other]] - caso contrário, isso é um bug e o build de bootstrap de três estágios foi projetado para capturar isso.
Pmdj
19
@pmjordan: "se não, isso é um bug" ou, menos provavelmente, um backdoor desonesto no processo de introdução ("Reflexões sobre a confiança confiável").
Steve Jessop
12
@lesleske: isso não é verdade. A saída binária da etapa 2 deve ser idêntica à saída binária da etapa 3, caso contrário, há um erro em algum lugar. O motivo é o que pmjordan diz: NewCompiler1 e NewCompiler2 são programas com fonte idêntica (a do NewCompiler). Eles recebem entrada idêntica (a fonte do NewCompiler). Portanto, eles produzirão saída idêntica, independentemente do compilador com o qual eles mesmos foram compilados (nesse caso, o NewCompiler1 foi compilado com o OldCompiler e o NewCompiler2 foi compilado com o NewCompiler1). Ou seja, NewCompiler2 e NewCompiler3 são binários idênticos.
21812 Steve Steveop
12
Você já se perguntou: e se perdêssemos todos os binários do compilador C? E teve que iniciar do zero? É assim que eu faria: existe o Tiny C Compiler (que na verdade pode compilar o kernel do Linux, por isso é um recurso completo). Todos os seus arquivos de origem C produzem meras 30k linhas de código, incluindo comentários. Embora até tenha sido um esforço, alguém que entenda C poderia aprender com as fontes, como gerar saída binária e "compilar" as fontes TCC manualmente (na verdade, estou pensando em cartões perfurados aqui). Em seguida, recompile o TCC com isso e use-o para inicializar o GCC ou similar.
datenwolf
11
@ datenwolf: algo assim, sim. Se pudermos supor que perdemos todos os binários do compilador C, mas ainda temos um assembler, então podemos escrever um programa assembler TinyTinyC. Seria um compilador C menos completo do que o TinyC: não precisamos que ele seja capaz de compilar o GCC ou o kernel do linux, precisamos apenas que ele seja capaz de compilar o TinyC. Em seguida, execute-o na fonte do TinyC, que nos fornece um compilador C capaz de compilar o Linux (e, esperamos, glibc e GCC) e estamos no negócio. Se nem sequer temos um assembler, primeiro inicializamos um desses, é mais fácil do que um compilador C.
21812 Steve Steveop