Skip to content

Commit 1293ce9

Browse files
committed
Explain stages in terms of the compiler currently running
1 parent fb88941 commit 1293ce9

File tree

1 file changed

+78
-111
lines changed

1 file changed

+78
-111
lines changed

src/building/bootstrapping.md

+78-111
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ first build the new compiler with an older compiler and then use that to
5757
build the new compiler with itself. For development, you usually only want
5858
the `stage1` compiler: `x.py build library/std`.
5959

60+
For more information about stages, see <#understanding-stages-of-bootstrap> below.
61+
6062
## Complications of bootstrapping
6163

6264
Since the build system uses the current beta compiler to build the stage-1
@@ -108,50 +110,89 @@ contribution [here][bootstrap-build].
108110

109111
## Understanding stages of bootstrap
110112

111-
This is a detailed look into the separate bootstrap stages. When running
112-
`x.py` you will see output such as:
113-
114-
```txt
115-
Building stage0 std artifacts
116-
Copying stage0 std from stage0
117-
Building stage0 compiler artifacts
118-
Copying stage0 rustc from stage0
119-
Building LLVM for x86_64-apple-darwin
120-
Building stage0 codegen artifacts
121-
Assembling stage1 compiler
122-
Building stage1 std artifacts
123-
Copying stage1 std from stage1
124-
Building stage1 compiler artifacts
125-
Copying stage1 rustc from stage1
126-
Building stage1 codegen artifacts
127-
Assembling stage2 compiler
128-
Uplifting stage1 std
129-
Copying stage2 std from stage1
130-
Generating unstable book md files
131-
Building stage0 tool unstable-book-gen
132-
Building stage0 tool rustbook
133-
Documenting standalone
134-
Building rustdoc for stage2
135-
Documenting book redirect pages
136-
Documenting stage2 std
137-
Building rustdoc for stage1
138-
Documenting stage2 whitelisted compiler
139-
Documenting stage2 compiler
140-
Documenting stage2 rustdoc
141-
Documenting error index
142-
Uplifting stage1 rustc
143-
Copying stage2 rustc from stage1
144-
Building stage2 tool error_index_generator
145-
```
113+
### Overview
114+
115+
This is a detailed look into the separate bootstrap stages.
116+
117+
The convention `x.py` uses is that:
118+
- A `--stage N` flag means to run the stage N compiler (`stageN/rustc`).
119+
- A "stage N artifact" is an artifact that is _produced_ by the stage N compiler.
120+
- The "stage (N+1) compiler" is assembled from "stage N artifacts". This process is called _uplifting_.
121+
122+
For example, `x.py build --stage 0` means to build with the beta `rustc`, and
123+
`test --stage 0` isn't really meaningful (it's not running tests on your changes,
124+
but on `beta`, so it always fails). Similarly, `doc --stage 0` means to
125+
document using the beta `rustdoc`.
126+
127+
Note that this implies the stage N compiler is _not_ the same as the compiler
128+
built by `build --stage N compiler/rustc` -- that's 'stage N artifacts'
129+
('the compiler built by stage N').
130+
131+
In short, _stage 0 uses the stage0 compiler to create stage0 artifacts which
132+
will later be uplifted to stage1_.
133+
134+
In each stage, two major steps are performed:
135+
136+
1. `std` is compiled by the stage N compiler.
137+
2. That `std` is linked to programs built by the stage N compiler, including the stage (N+1) compiler.
138+
139+
This is somewhat intuitive if one thinks of the stage (N+1) compiler as "just"
140+
another program we are building with the stage N compiler:
141+
`build --stage N compiler/rustc` is linking the stage (N+1) compiler to the `std`
142+
built by the stage N compiler.
146143

147-
A deeper look into `x.py`'s phases can be seen here:
144+
Here is a chart of a full build using x.py:
148145

149146
<img alt="A diagram of the rustc compilation phases" src="../img/rustc_stages.svg" class="center" />
150147

151148
Keep in mind this diagram is a simplification, i.e. `rustdoc` can be built at
152149
different stages, the process is a bit different when passing flags such as
153150
`--keep-stage`, or if there are non-host targets.
154151

152+
The stage 1 artifacts are what is shipped to end-users, including `stage2/bin/rustc`.
153+
154+
### Stages and libstd
155+
156+
Note that there are two `std` libraries in play here:
157+
1. The library _linked_ to `stageN/rustc`, which was built by stage N-1 (stage N-1 `std`)
158+
2. The library _used to compile programs_ with `stageN/rustc`, which was built by stage N (stage N `std`).
159+
160+
stage N `std` is pretty much necessary for any useful work with the compiler.
161+
Without it, you can only compile programs with `#![no_core]` -- not terribly useful!
162+
163+
The reason these need to be different is because they aren't necessarily ABI-compatible:
164+
there could be a new layout optimization on nightly that isn't present in `beta`.
165+
166+
This is also where `--keep-stage 1 library/std` comes into play. Since most
167+
changes to the compiler don't actually change the ABI, once you've produced a
168+
`std` in stage 1, you can probably just reuse it with a different compiler.
169+
If the ABI hasn't changed, you're good to go, no need to spend the time
170+
recompiling that `std`.
171+
`--keep-stage` simply assumes the previous compile is fine and copies those
172+
artifacts into the appropriate place, skipping the cargo invocation.
173+
174+
### Cross-compiling
175+
176+
Building stage2 `std` is different depending on whether you are cross-compiling or not
177+
(see in the table how stage2 only builds non-host `std` targets).
178+
This is because `x.py` uses a trick: if `HOST` and `TARGET` are the same,
179+
it will reuse stage1 `std` for stage2! This is sound because stage1 `std`
180+
was compiled with the stage1 compiler, i.e. a compiler using the source code
181+
you currently have checked out. So it should be identical (and therefore ABI-compatible)
182+
to the `std` that `stage2/rustc` would compile.
183+
184+
However, when cross-compiling, stage1 `std` will only run on the host.
185+
So the stage2 compiler has to recompile `std` for the target.
186+
187+
### Why does only libstd use cfg(bootstrap)?
188+
189+
The `rustc` generated by the stage0 compiler is linked to the freshly-built
190+
`std`, which means that for the most part only `std` needs to be cfg-gated,
191+
so that `rustc` can use features added to std immediately after their addition,
192+
without need for them to get into the downloaded beta.
193+
194+
### Directories and artifacts generated by x.py
195+
155196
The following tables indicate the outputs of various stage actions:
156197

157198
| Stage 0 Action | Output |
@@ -164,7 +205,7 @@ The following tables indicate the outputs of various stage actions:
164205
| copy `stage0-rustc (except executable)` | `build/HOST/stage0-sysroot/lib/rustlib/HOST` |
165206
| build `llvm` | `build/HOST/llvm` |
166207
| `stage0` builds `codegen` with `stage0-sysroot` | `build/HOST/stage0-codegen/HOST` |
167-
| `stage0` builds `rustdoc` with `stage0-sysroot` | `build/HOST/stage0-tools/HOST` |
208+
| `stage0` builds `rustdoc`, `clippy`, `miri`, with `stage0-sysroot` | `build/HOST/stage0-tools/HOST` |
168209

169210
`--stage=0` stops here.
170211

@@ -192,80 +233,6 @@ The following tables indicate the outputs of various stage actions:
192233

193234
`--stage=2` stops here.
194235

195-
Note that the convention `x.py` uses is that:
196-
- A "stage N artifact" is an artifact that is _produced_ by the stage N compiler.
197-
- The "stage (N+1) compiler" is assembled from "stage N artifacts".
198-
- A `--stage N` flag means build _with_ stage N.
199-
200-
In short, _stage 0 uses the stage0 compiler to create stage0 artifacts which
201-
will later be uplifted to stage1_.
202-
203-
Every time any of the main artifacts (`std` and `rustc`) are compiled, two
204-
steps are performed.
205-
When `std` is compiled by a stage N compiler, that `std` will be linked to
206-
programs built by the stage N compiler (including `rustc` built later
207-
on). It will also be used by the stage (N+1) compiler to link against itself.
208-
This is somewhat intuitive if one thinks of the stage (N+1) compiler as "just"
209-
another program we are building with the stage N compiler. In some ways, `rustc`
210-
(the binary, not the `rustbuild` step) could be thought of as one of the few
211-
`no_core` binaries out there.
212-
213-
So "stage0 std artifacts" are in fact the output of the downloaded stage0
214-
compiler, and are going to be used for anything built by the stage0 compiler:
215-
e.g. `rustc` artifacts. When it announces that it is "building stage1
216-
std artifacts" it has moved on to the next bootstrapping phase. This pattern
217-
continues in latter stages.
218-
219-
Also note that building host `std` and target `std` are different based on the
220-
stage (e.g. see in the table how stage2 only builds non-host `std` targets.
221-
This is because during stage2, the host `std` is uplifted from the "stage 1"
222-
`std` -- specifically, when "Building stage 1 artifacts" is announced, it is
223-
later copied into stage2 as well (both the compiler's `libdir` and the
224-
`sysroot`).
225-
226-
This `std` is pretty much necessary for any useful work with the compiler.
227-
Specifically, it's used as the `std` for programs compiled by the newly compiled
228-
compiler (so when you compile `fn main() { }` it is linked to the last `std`
229-
compiled with `x.py build library/std`).
230-
231-
The `rustc` generated by the stage0 compiler is linked to the freshly-built
232-
`std`, which means that for the most part only `std` needs to be cfg-gated,
233-
so that `rustc` can use featured added to std immediately after their addition,
234-
without need for them to get into the downloaded beta. The `std` built by the
235-
`stage1/bin/rustc` compiler, also known as "stage1 std artifacts", is not
236-
necessarily ABI-compatible with that compiler.
237-
That is, the `rustc` binary most likely could not use this `std` itself.
238-
It is however ABI-compatible with any programs that the `stage1/bin/rustc`
239-
binary builds (including itself), so in that sense they're paired.
240-
241-
This is also where `--keep-stage 1 library/std` comes into play. Since most
242-
changes to the compiler don't actually change the ABI, once you've produced a
243-
`std` in stage 1, you can probably just reuse it with a different compiler.
244-
If the ABI hasn't changed, you're good to go, no need to spend the time
245-
recompiling that `std`.
246-
`--keep-stage` simply assumes the previous compile is fine and copies those
247-
artifacts into the appropriate place, skipping the cargo invocation.
248-
249-
The reason we first build `std`, then `rustc`, is largely just
250-
because we want to minimize `cfg(stage0)` in the code for `rustc`.
251-
Currently `rustc` is always linked against a "new" `std` so it doesn't
252-
ever need to be concerned with differences in std; it can assume that the std is
253-
as fresh as possible.
254-
255-
The reason we need to build it twice is because of ABI compatibility.
256-
The beta compiler has it's own ABI, and then the `stage1/bin/rustc` compiler
257-
will produce programs/libraries with the new ABI.
258-
We used to build three times, but because we assume that the ABI is constant
259-
within a codebase, we presume that the libraries produced by the "stage2"
260-
compiler (produced by the `stage1/bin/rustc` compiler) is ABI-compatible with
261-
the `stage1/bin/rustc` compiler's produced libraries.
262-
What this means is that we can skip that final compilation -- and simply use the
263-
same libraries as the `stage2/bin/rustc` compiler uses itself for programs it
264-
links against.
265-
266-
This `stage2/bin/rustc` compiler is shipped to end-users, along with the
267-
`stage 1 {std,rustc}` artifacts.
268-
269236
## Passing stage-specific flags to `rustc`
270237

271238
`x.py` allows you to pass stage-specific flags to `rustc` when bootstrapping.

0 commit comments

Comments
 (0)