Edit introduction to bootstrapping
Use paragraphs instead of bullet-points. Edits throughout for clarity. Use semantic line breaks in edited sections. Co-authored-by: Joshua Nelson <github@jyn.dev>
This commit is contained in:
parent
c0c8c133c7
commit
b547c04d8e
|
|
@ -2,11 +2,8 @@
|
||||||
|
|
||||||
<!-- toc -->
|
<!-- toc -->
|
||||||
|
|
||||||
This subchapter is about the bootstrapping process.
|
|
||||||
|
|
||||||
## What is bootstrapping? How does it work?
|
[*Bootstrapping*] is the process of using a compiler to compile itself.
|
||||||
|
|
||||||
[Bootstrapping] is the process of using a compiler to compile itself.
|
|
||||||
More accurately, it means using an older compiler to compile a newer version
|
More accurately, it means using an older compiler to compile a newer version
|
||||||
of the same compiler.
|
of the same compiler.
|
||||||
|
|
||||||
|
|
@ -21,45 +18,53 @@ rustc, then uses it to compile the new compiler.
|
||||||
|
|
||||||
## Stages of bootstrapping
|
## Stages of bootstrapping
|
||||||
|
|
||||||
Compiling `rustc` is done in stages:
|
Compiling `rustc` is done in stages.
|
||||||
|
|
||||||
- **Stage 0:** the stage0 compiler is usually (you can configure `x.py` to use
|
### Stage 0
|
||||||
something else) the current _beta_ `rustc` compiler and its associated dynamic
|
|
||||||
libraries (which `x.py` will download for you). This stage0 compiler is then
|
|
||||||
used only to compile `rustbuild`, `std`, and `rustc`. When compiling
|
|
||||||
`rustc`, this stage0 compiler uses the freshly compiled `std`.
|
|
||||||
There are two concepts at play here: a compiler (with its set of dependencies)
|
|
||||||
and its 'target' or 'object' libraries (`std` and `rustc`).
|
|
||||||
Both are staged, but in a staggered manner.
|
|
||||||
- **Stage 1:** the code in your clone (for new version) is then
|
|
||||||
compiled with the stage0 compiler to produce the stage1 compiler.
|
|
||||||
However, it was built with an older compiler (stage0), so to
|
|
||||||
optimize the stage1 compiler we go to the next stage.
|
|
||||||
- In theory, the stage1 compiler is functionally identical to the
|
|
||||||
stage2 compiler, but in practice there are subtle differences. In
|
|
||||||
particular, the stage1 compiler itself was built by stage0 and
|
|
||||||
hence not by the source in your working directory: this means that
|
|
||||||
the symbol names used in the compiler source may not match the
|
|
||||||
symbol names that would have been made by the stage1 compiler. This is
|
|
||||||
important when using dynamic linking and the lack of ABI compatibility
|
|
||||||
between versions. This primarily manifests when tests try to link with any
|
|
||||||
of the `rustc_*` crates or use the (now deprecated) plugin infrastructure.
|
|
||||||
These tests are marked with `ignore-stage1`.
|
|
||||||
- **Stage 2:** we rebuild our stage1 compiler with itself to produce
|
|
||||||
the stage2 compiler (i.e. it builds itself) to have all the _latest
|
|
||||||
optimizations_. (By default, we copy the stage1 libraries for use by
|
|
||||||
the stage2 compiler, since they ought to be identical.)
|
|
||||||
- _(Optional)_ **Stage 3**: to sanity check our new compiler, we
|
|
||||||
can build the libraries with the stage2 compiler. The result ought
|
|
||||||
to be identical to before, unless something has broken.
|
|
||||||
|
|
||||||
The `stage2` compiler is the one distributed with `rustup` and all other
|
The stage0 compiler is usually the current _beta_ `rustc` compiler
|
||||||
install methods. However, it takes a very long time to build because one must
|
and its associated dynamic libraries,
|
||||||
first build the new compiler with an older compiler and then use that to
|
which `x.py` will download for you.
|
||||||
build the new compiler with itself. For development, you usually only want
|
(You can also configure `x.py` to use something else.)
|
||||||
the `stage1` compiler: `x.py build library/std`.
|
|
||||||
|
|
||||||
### Default stages
|
The stage0 compiler is then used only to compile `rustbuild`, `std`, and `rustc`.
|
||||||
|
When compiling `rustc`, the stage0 compiler uses the freshly compiled `std`.
|
||||||
|
There are two concepts at play here:
|
||||||
|
a compiler (with its set of dependencies)
|
||||||
|
and its 'target' or 'object' libraries (`std` and `rustc`).
|
||||||
|
Both are staged, but in a staggered manner.
|
||||||
|
|
||||||
|
### Stage 1
|
||||||
|
|
||||||
|
The rustc source code is then compiled with the stage0 compiler to produce the stage1 compiler.
|
||||||
|
|
||||||
|
### Stage 2
|
||||||
|
|
||||||
|
We then rebuild our stage1 compiler with itself to produce the stage2 compiler.
|
||||||
|
|
||||||
|
In theory, the stage1 compiler is functionally identical to the stage2 compiler,
|
||||||
|
but in practice there are subtle differences.
|
||||||
|
In particular, the stage1 compiler itself was built by stage0
|
||||||
|
and hence not by the source in your working directory.
|
||||||
|
This means that the symbol names used in the compiler source
|
||||||
|
may not match the symbol names that would have been made by the stage1 compiler,
|
||||||
|
which can cause problems for dynamic libraries and tests.
|
||||||
|
|
||||||
|
The `stage2` compiler is the one distributed with `rustup` and all other install methods.
|
||||||
|
However, it takes a very long time to build
|
||||||
|
because one must first build the new compiler with an older compiler
|
||||||
|
and then use that to build the new compiler with itself.
|
||||||
|
For development, you usually only want the `stage1` compiler,
|
||||||
|
which you can build with `x.py build library/std`.
|
||||||
|
See [Building the Compiler](/building/how-to-build-and-run.html#building-the-compiler).
|
||||||
|
|
||||||
|
### Stage 3
|
||||||
|
|
||||||
|
Stage 3 is optional. To sanity check our new compiler, we
|
||||||
|
can build the libraries with the stage2 compiler. The result ought
|
||||||
|
to be identical to before, unless something has broken.
|
||||||
|
|
||||||
|
### Building the stages
|
||||||
|
|
||||||
`x.py` tries to be helpful and pick the stage you most likely meant for each subcommand.
|
`x.py` tries to be helpful and pick the stage you most likely meant for each subcommand.
|
||||||
These defaults are as follows:
|
These defaults are as follows:
|
||||||
|
|
@ -132,9 +137,10 @@ contribution [here][bootstrap-build].
|
||||||
This is a detailed look into the separate bootstrap stages.
|
This is a detailed look into the separate bootstrap stages.
|
||||||
|
|
||||||
The convention `x.py` uses is that:
|
The convention `x.py` uses is that:
|
||||||
|
|
||||||
- A `--stage N` flag means to run the stage N compiler (`stageN/rustc`).
|
- A `--stage N` flag means to run the stage N compiler (`stageN/rustc`).
|
||||||
- A "stage N artifact" is a build artifact that is _produced_ by the stage N compiler.
|
- A "stage N artifact" is a build artifact that is _produced_ by the stage N compiler.
|
||||||
- The "stage (N+1) compiler" is assembled from "stage N artifacts". This
|
- The stage N+1 compiler is assembled from stage N *artifacts*. This
|
||||||
process is called _uplifting_.
|
process is called _uplifting_.
|
||||||
|
|
||||||
#### Build artifacts
|
#### Build artifacts
|
||||||
|
|
@ -174,11 +180,10 @@ Build artifacts include, but are not limited to:
|
||||||
library/std` instead, which allows compiling programs without needing to define
|
library/std` instead, which allows compiling programs without needing to define
|
||||||
lang items.
|
lang items.
|
||||||
|
|
||||||
### Building vs. Running
|
### Building vs. running
|
||||||
|
|
||||||
|
|
||||||
Note that `build --stage N compiler/rustc` **does not** build the stage N compiler:
|
Note that `build --stage N compiler/rustc` **does not** build the stage N compiler:
|
||||||
instead it builds the stage _N+1_ compiler _using_ the stage N compiler.
|
instead it builds the stage N+1 compiler _using_ the stage N compiler.
|
||||||
|
|
||||||
In short, _stage 0 uses the stage0 compiler to create stage0 artifacts which
|
In short, _stage 0 uses the stage0 compiler to create stage0 artifacts which
|
||||||
will later be uplifted to be the stage1 compiler_.
|
will later be uplifted to be the stage1 compiler_.
|
||||||
|
|
@ -186,8 +191,8 @@ will later be uplifted to be the stage1 compiler_.
|
||||||
In each stage, two major steps are performed:
|
In each stage, two major steps are performed:
|
||||||
|
|
||||||
1. `std` is compiled by the stage N compiler.
|
1. `std` is compiled by the stage N compiler.
|
||||||
2. That `std` is linked to programs built by the stage N compiler, including
|
2. That `std` is linked to programs built by the stage N compiler,
|
||||||
the stage N artifacts (stage (N+1) compiler).
|
including the stage N artifacts (stage N+1 compiler).
|
||||||
|
|
||||||
This is somewhat intuitive if one thinks of the stage N artifacts as "just"
|
This is somewhat intuitive if one thinks of the stage N artifacts as "just"
|
||||||
another program we are building with the stage N compiler:
|
another program we are building with the stage N compiler:
|
||||||
|
|
@ -202,8 +207,6 @@ Keep in mind this diagram is a simplification, i.e. `rustdoc` can be built at
|
||||||
different stages, the process is a bit different when passing flags such as
|
different stages, the process is a bit different when passing flags such as
|
||||||
`--keep-stage`, or if there are non-host targets.
|
`--keep-stage`, or if there are non-host targets.
|
||||||
|
|
||||||
The stage 2 compiler is what is shipped to end-users.
|
|
||||||
|
|
||||||
### Stages and `std`
|
### Stages and `std`
|
||||||
|
|
||||||
Note that there are two `std` libraries in play here:
|
Note that there are two `std` libraries in play here:
|
||||||
|
|
@ -226,10 +229,12 @@ recompiling that `std`.
|
||||||
`--keep-stage` simply assumes the previous compile is fine and copies those
|
`--keep-stage` simply assumes the previous compile is fine and copies those
|
||||||
artifacts into the appropriate place, skipping the cargo invocation.
|
artifacts into the appropriate place, skipping the cargo invocation.
|
||||||
|
|
||||||
### Cross-compiling
|
### Cross-compiling rustc
|
||||||
|
|
||||||
|
*Cross-compiling* is the process of compiling code that will run on another archicture.
|
||||||
|
For instance, you might want to build an ARM version of rustc using an x86 machine.
|
||||||
|
Building stage2 `std` is different when you are cross-compiling.
|
||||||
|
|
||||||
Building stage2 `std` is different depending on whether you are cross-compiling or not
|
|
||||||
(see in the table how stage2 only builds non-host `std` targets).
|
|
||||||
This is because `x.py` uses a trick: if `HOST` and `TARGET` are the same,
|
This is because `x.py` uses a trick: if `HOST` and `TARGET` are the same,
|
||||||
it will reuse stage1 `std` for stage2! This is sound because stage1 `std`
|
it will reuse stage1 `std` for stage2! This is sound because stage1 `std`
|
||||||
was compiled with the stage1 compiler, i.e. a compiler using the source code
|
was compiled with the stage1 compiler, i.e. a compiler using the source code
|
||||||
|
|
@ -239,6 +244,8 @@ to the `std` that `stage2/rustc` would compile.
|
||||||
However, when cross-compiling, stage1 `std` will only run on the host.
|
However, when cross-compiling, stage1 `std` will only run on the host.
|
||||||
So the stage2 compiler has to recompile `std` for the target.
|
So the stage2 compiler has to recompile `std` for the target.
|
||||||
|
|
||||||
|
(See in the table how stage2 only builds non-host `std` targets).
|
||||||
|
|
||||||
### Why does only libstd use `cfg(bootstrap)`?
|
### Why does only libstd use `cfg(bootstrap)`?
|
||||||
|
|
||||||
The `rustc` generated by the stage0 compiler is linked to the freshly-built
|
The `rustc` generated by the stage0 compiler is linked to the freshly-built
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue