如何引导GCC和g ++?


185

这一直困扰着我一段时间。GCC和g ++如何自行编译?

我猜每个修订都使用以前构建的修订进行编译。这是真的?如果是的话,是否意味着最旧的g ++和GCC版本是用汇编编写的?


13
每个修订最终都可以自己编译。:)
Martin Hennings 2012年

4
如果您想了解第一个编译器是如何产生的,那么阅读这本书很有趣。
parkovski 2012年

1
@parkovski链接消失了吗?
Nubcake

Answers:


175

GCC的最旧版本是使用另一个C编译器编译的,因为编写它时还有其他版本。有史以来第一个C编译器(于1973年,IIRC)是以PDP-11汇编或以其之前的B编程语言实现的,但是无论如何,B编译器都是以汇编形式编写的。同样,第一个C ++编译器(CPre / Cfront,1979-1983)可能首先用C实现,然后用C ++重写。

当您编译GCC或任何其他自托管编译器时,完整的构建顺序为:

  1. 使用现有的C编译器构建新版本的GCC
  2. 用您刚刚构建的版本重新构建新版本的GCC
  3. (可选)重复第2步以进行验证。

此过程称为自举。它测试编译器自身的编译能力,并确保生成的编译器使用其自身实现的所有优化进行构建。

编辑:Drew Dormann在评论中指出Bjarne Stroustrup 对C ++最早实现的描述。它是用C ++实现的,但是被Stroustrup称为从C ++到C的“预处理器”进行了翻译。按照他的定义,它不是一个完整的编译器,但是C ++仍然是用C语言引导的。


19
引导程序构建过程的三步版本确实是用于验证:编译器本身用作其自己的测试用例。GCC编译[其他]应该产生相同的结果(相同的二进制文件,贴现宏像__DATE____TIME__其连的调用之间变化相同编译器)作为GCC编译[GCC编译[其他]] -如果不是,这是一个错误,并3阶段引导程序构建旨在抓住这一点。
pmdj

19
@pmjordan:“如果没有,那就是一个错误”,或者在引入过程中不太可能是一个曲折的后门(“对信任的反思”)。
史蒂夫·杰索普

12
@sleske:那是不对的。步骤2的二进制输出必须与步骤3的二进制输出相同,否则,某处存在错误。原因是因为pmjordan所说:NewCompiler1和NewCompiler2是具有相同源(NewCompiler的源)的程序。它们具有相同的输入(NewCompiler的源)。因此,无论使用哪种编译器本身,它们都将产生相同的输出(在这种情况下,NewCompiler1是使用OldCompiler编译的,而NewCompiler2是使用NewCompiler1编译的)。也就是说,NewCompiler2和NewCompiler3是二进制相同的。
史蒂夫·杰索普

12
我曾经想过:如果我们丢失所有C编译器二进制文件怎么办?不得不从头开始?这就是我的处理方式:有Tiny C编译器(它实际上可以编译Linux内核,因此功能相当完整)。它所有的C源文件仅包含3万行代码,包括注释。尽管付出了相当大的努力,但了解C的人还是可以从源中学习如何生成二进制输出并手动“编译” TCC源(我在这里实际上想到的是打孔卡)。然后用它重新编译TCC,并用它来引导GCC或类似的程序。
datenwolf 2012年

11
@datenwolf:是的,是的。如果可以假定我们丢失了所有C编译器二进制文件,但是仍然有一个汇编程序,则可以编写一个汇编程序TinyTinyC。与TinyC相比,这将是一个功能较差的C编译器:我们不需要它就能编译GCC或linux内核,我们只需要它就能编译TinyC。然后在TinyC的源代码上运行它,这将为我们提供一个能够编译Linux(以及希望的glibc和GCC)的C编译器,并且我们可以开展业务。如果我们什至没有汇编程序,那么我们将首先引导其中的一个,它比C编译器容易。
史蒂夫·杰索普
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.