Bootstrapping (compilers)

In computer science, bootstrapping is the technique for producing a self-compiling compiler — that is, compiler (or assembler) written in the source programming language that it intends to compile. An initial core version of the compiler (the bootstrap compiler) is generated in a different language (which could be assembly language); successive expanded versions of the compiler are developed using this minimal subset of the language. The problem of compiling a self-compiling compiler has been called the chicken-or-egg problem in compiler design, and bootstrapping is a solution to this problem.[1][2]

Many compilers for many programming languages are bootstrapped, including compilers for BASIC, ALGOL, C, C#, D, Pascal, PL/I, Factor, Haskell, Modula-2, Oberon, OCaml, Common Lisp, Scheme, Go, Java, Elixir, Rust, Python, Scala, Nim, Eiffel, and more.

Process

A typical bootstrap process work in three or four stages:[3][4][5]

  • Stage 0: preparing an environment for the bootstrap compiler to work with.
  • Stage 1: the bootstrap compiler is produced.
  • Stage 2: a full compiler is produced by the bootstrap compiler.
  • Stage 3: a full compiler is produced by the stage 2 full compiler.

The full compiler is built twice in order to compare the outputs of the two stages. If they are different, either the bootstrap or the full compiler contains a bug.[3]

Advantages

Bootstrapping a compiler has the following advantages:[6][7]

  • it is a non-trivial test of the language being compiled, and as such is a form of dogfooding.
  • compiler developers and bug reporters only need to know the language being compiled.
  • compiler development can be performed in the higher-level language being compiled.
  • improvements to the compiler's back-end improve not only general-purpose programs but also the compiler itself.
  • it is a comprehensive consistency check as it should be able to reproduce its own object code.

Note that some of these points assume that the language runtime is also written in the same language.

Methods

If one needs to compile a compiler for language X written in language X, there is the issue of how the first compiler can be compiled. The different methods that are used in practice include:

  • Implementing an interpreter or compiler for language X in language Y. Niklaus Wirth reported that he wrote the first Pascal compiler in Fortran.
  • Another interpreter or compiler for X has already been written in another language Y; this is how Scheme is often bootstrapped.
  • Earlier versions of the compiler were written in a subset of X for which there existed some other compiler; this is how some supersets of Java, Haskell, and the initial Free Pascal compiler are bootstrapped.
  • A compiler supporting non-standard language extensions or optional language features can be written without using those extensions and features, to enable it being compiled with another compiler supporting the same base language but a different set of extensions and features. The main parts of the C++ compiler clang were written in a subset of C++ that can be compiled by both g++ and Microsoft Visual C++. Advanced features are written with some GCC extensions.
  • The compiler for X is cross compiled from another architecture where there exists a compiler for X; this is how compilers for C are usually ported to other platforms. Also this is the method used for Free Pascal after the initial bootstrap.
  • Writing the compiler in X; then hand-compiling it from source (most likely in a non-optimized way) and running that on the code to get an optimized compiler. Donald Knuth used this for his WEB literate programming system.

Methods for distributing compilers in source code include providing a portable bytecode version of the compiler, so as to bootstrap the process of compiling the compiler with itself. The T-diagram is a notation used to explain these compiler bootstrap techniques.[7] In some cases, the most convenient way to get a complicated compiler running on a system that has little or no software on it involves a series of ever more sophisticated assemblers and compilers.[8]

History

Assemblers were the first language tools to bootstrap themselves.

The first high-level language to provide such a bootstrap was NELIAC in 1958. The first widely used languages to do so were Burroughs B5000 Algol in 1961 and LISP in 1962.

Hart and Levin wrote a LISP compiler in LISP at MIT in 1962, testing it inside an existing LISP interpreter. Once they had improved the compiler to the point where it could compile its own source code, it was self-hosting.[9]

The compiler as it exists on the standard compiler tape is a machine language program that was obtained by having the S-expression definition of the compiler work on itself through the interpreter.

AI Memo 39[9]

This technique is only possible when an interpreter already exists for the very same language that is to be compiled. It borrows directly from the notion of running a program on itself as input, which is also used in various proofs in theoretical computer science, such as the proof that the halting problem is undecidable.

Current efforts

Due to security concerns regarding the Trusting Trust Attack and various attacks against binary trustworthiness, multiple projects are working to reduce the effort for not only bootstrapping from source but also allowing everyone to verify that source and executable correspond. These include the Bootstrappable builds project[10] and the Reproducible builds project.[11]

List of languages having self-hosting compilers

The following programming languages have self-hosting compilers:

See also

References

  1. Reynolds, John H. (December 2003). "Bootstrapping a self-compiling compiler from machine X to machine Y". CCSC: Eastern Conference. Journal of Computing Sciences in Colleges. 19 (2): 175–181. 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?
  2. Glück, Robert (2012). "Bootstrapping compiler generators from partial evaluators". In Clarke, Edmund; Virbitskaite, Irina; Voronkov, Andrei (eds.). 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. Springer. pp. 125–141. 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. "Installing GCC: Building". GNU Project - Free Software Foundation (FSF).
  4. "rust-lang/rust: bootstrap". GitHub.
  5. "Advanced Build Configurations — LLVM 10 documentation". llvm.org.
  6. Compilers and Compiler Generators: An Introduction With C++. Patrick D. Terry 1997. International Thomson Computer Press. ISBN 1-85032-298-8
  7. "Compiler Construction and Bootstrapping" by P.D.Terry 2000. HTML Archived 2009-11-23 at the Wayback Machine. PDF Archived December 14, 2010, at the Wayback Machine.
  8. "Bootstrapping a simple compiler from nothing" Archived March 3, 2010, at the Wayback Machine by Edmund GRIMLEY EVANS 2001
  9. Tim Hart and Mike Levin. "AI Memo 39-The new compiler" (PDF). Archived from the original (PDF) on 2011-02-24. Retrieved 2008-05-23.
  10. http://bootstrappable.org/
  11. https://reproducible-builds.org/
  12. https://www.pyret.org Archived 2018-04-10 at the Wayback Machine
  13. "Archived copy". Archived from the original on 2017-06-04. Retrieved 2017-09-19.CS1 maint: archived copy as title (link)
  14. "Archived copy". Archived from the original on 2014-12-28. Retrieved 2015-05-27.CS1 maint: archived copy as title (link)
This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.