自举 (编译器)
编程语言使用自身编写出能编译自己语言的编译器的过程
此条目可参照英语维基百科相应条目来扩充。 (2023年12月8日) |
在电脑科学中,自举是一种自生成编译器的技术——也就是,某个编程语言的编译器(或汇编器)是由该语言编写的。最初的核心编译器(自举编译器)是由其他编程语言生成的(可以是使用汇编语言),而之后版本的编译器则是使用该语言的最小子集编写而成。自生成编译器的编译问题被称为编译器设计的先有鸡还是先有蛋问题,而自举则是这个问题的解决方法。[1][2]
自举对于创建一个新的编程语言是很普遍的做法,有很多编程语言已经实现了自举。
步骤
- 步骤0:准备自举编译器的工作环境,选择自举编译器的编程语言和输出语言。在裸机(也就是没有任何语言的编译器)的情况下,原始码和输出代码需被编写为二进制机器代码,或者可以通过在目标机器之外的其他机器上交叉编译来创建。否则,该语言的自举编译器必选使用目标机器上存在的一种语言编写而成,并且将生成可以在目标机器上执行的东西,包括高级编程语言、汇编语言、对象文件、甚至机器代码。
- 步骤1:生成自举编译器。这个编译器能够将自己的原始码编译成能在目标机器上运行的程序,之后的语言开发将会在这个自举编译器所支持的语言上拓展,进入步骤2。
- 步骤2:使用自举编译器生成全功能编译器。通常是分阶段进行的,比如语言版本X的编译器能够支持语言版本X+1的功能,但自己不会使用这些功能。一旦这个编译器完成测试并可自行编译后,则现在语言版本X+1的功能可能会被编译器的后续版本使用。
- 步骤3:使用步骤2的编译器生成全功能编译器。如果需要添加新的语言功能,则从步骤2重新开始。从这时候开始,可以使用步骤3生成的编译器代替自举编译器来继续该语言的开发。
全功能编译器被构建了两次,用于比较两个阶段的输出。 如果它们有不同,则自举编译器或者全功能编译器存在缺陷。[3]
优点
- 通过吃自己的狗粮的方式,对正在编译的语言进行测试,而且这很重要。
- 编译器开发人员和缺陷报告人员只需要知道当前编译的语言。
- 编译器的开发可以在当前编译的高级编程语言上进行。
- 对编译器后端的改进,不仅改进了通用程序,而且改进了编译器本身。
- 这是一个全面的一致性检查,因为它应该能够重现自己的目标代码。
请注意,其中一些要点是假设语言的运行时也是用相同的语言编写的。
方法
如果需要用X语言编写一个X语言的编译器,那就会出现“如何编译出该语言的第一个编译器”的问题了。通常会有以下方法:
- 使用Y语言实现X语言的编译器或解释器。例如尼克劳斯·维尔特就是用Fortran编译出第一个Pascal的编译器。[8]
- X语言的另一个编译器或解析器由Y语言编写成,例如Scheme。
- 编译器的早期版本是使用该语言的最小子集编写成,例如Java、Haskell、Free Pascal。
- 支持非标准语言扩展或可选语言功能的编译器可以在不使用这些扩展和功能的情况下编写,以使其能够与另一个支持相同的语言基础部分,但有不同的扩展和功能的编译器一起编译。例如C++的编译器Clang的主要部分是由C++的子集编写的,可以被 G++或者Microsoft Visual C++的编译器编译。高级功能的支持是由一些GCC扩展编写的。
- X语言的编译器是由同语言但不同平台的编译器交叉编译得到的,这通常是C编译器移植到其他硬件平台用到的。Free Pascal完成编译器自举后也是这样继续开发的。
- 在语言X中编写编译器,但从原始码手动编译出来(不包括优化方法)并在其上面运行以获得优化的编译器。高德纳就是这样来进行WEB的文学编程。
历史
第一个自举编译器(不包括汇编器)是由 Hart 和 Levin 于 1962 年为 Lisp 编写的,他们使用 Lisp 编写了一个 Lisp 编译器。[9]
目前的改进
由于对基于信任的信任和二进制可信性的攻击的担忧,有一些项目在研究如何改进代码,使其能从原始码自行完成自举,并且让每个人验证原始码和可执行代码是否如实运作,这包括了可自举代码项目及可重生成代码项目。[10]
参考文献
- ^ Reynolds, John H. Bootstrapping a self-compiling compiler from machine X to machine Y. CCSC: Eastern Conference. Journal of Computing Sciences in Colleges. December 2003, 19 (2): 175–181 [2023-06-11]. (原始内容存档于2023-02-25).
The idea of a compiler written in the language it compiles stirs up the old 'chicken-or-the-egg' conundrum: Where does the first one come from?
- ^ Glück, Robert. Clarke, Edmund; Virbitskaite, Irina; Voronkov, Andrei , 编. Perspectives of Systems Informatics: 8th International Andrei Ershov Memorial Conference、PSI 2011、Novosibirsk、Russia、June 27 – July 1、2011、Revised Selected Papers. Lecture Notes in Computer Science 7162. Bootstrapping compiler generators from partial evaluators. Springer: 125–141. 2012. doi:10.1007/978-3-642-29709-0_13.
Getting started presents the chicken-and-egg problem familiar from compiler construction: one needs a compiler to bootstrap a compiler、and bootstrapping compiler generators is no exception.
- ^ 3.0 3.1 Installing GCC: Building. GNU Project - Free Software Foundation (FSF). [2023-06-11]. (原始内容存档于2023-08-22).
- ^ rust-lang/rust: bootstrap. GitHub. [2023-06-11]. (原始内容存档于2023-06-12) (英语).
- ^ Advanced Build Configurations — LLVM 10 documentation. llvm.org. [2023-06-11]. (原始内容存档于2023-08-09).
- ^ Compilers and Compiler Generators: An Introduction With C++. Patrick D. Terry 1997. International Thomson Computer Press. ISBN 1-85032-298-8
- ^ "Compiler Construction and Bootstrapping" by P.D.Terry 2000. HTML 互联网档案馆的存档,存档日期2009-11-23.. PDF 互联网档案馆的存档,存档日期December 14, 2010,..
- ^ Wirth, Niklaus. 50 years of Pascal. Communications of the ACM. 2021-02-22, 64 (3). ISSN 0001-0782. doi:10.1145/3447525.
- ^ Tim, Hart; Mike, Levin. AI Memo 39-The new compiler (PDF). (原始内容 (PDF)存档于2021-07-26).
- ^ Reproducible Builds — a set of software development practices that create an independently-verifiable path from source to binary code. reproducible-builds.org. [2023-06-11]. (原始内容存档于2016-05-20).