Skip to content

Commit a2ad0a8

Browse files
committed
document keep-stage1
1 parent 732dc47 commit a2ad0a8

File tree

1 file changed

+100
-34
lines changed

1 file changed

+100
-34
lines changed

src/how-to-build-and-run.md

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,21 @@ One thing to keep in mind is that `rustc` is a _bootstrapping_ compiler. That
5353
is, since `rustc` is written in Rust, we need to use an older version of the
5454
compiler to compile the newer version. In particular, the newer version of the
5555
compiler, `libstd`, and other tooling may use some unstable features
56-
internally. The result is the compiling `rustc` is done in stages.
57-
58-
- **Stage 0:** the stage0 compiler can be your existing
59-
(perhaps older version of)
60-
Rust compiler, the current _beta_ compiler or you may download the binary
61-
from the internet.
62-
- **Stage 1:** the code in your clone (for new version)
63-
is then compiled with the stage0
64-
compiler to produce the stage1 compiler.
65-
However, it was built with an older compiler (stage0),
66-
so to optimize the stage1 compiler we go to next stage.
67-
- **Stage 2:** we rebuild our stage1 compiler with itself
68-
to produce the stage2 compiler (i.e. it builds
69-
itself) to have all the _latest optimizations_.
70-
- _(Optional)_ **Stage 3**: to sanity check of our new compiler,
71-
we can build it again
72-
with stage2 compiler which must be identical to itself,
73-
unless something has broken.
56+
internally. The result is the compiling `rustc` is done in stages:
57+
58+
- **Stage 0:** the stage0 compiler is usually the current _beta_ compiler
59+
(`x.py` will download it for you); you can configure `x.py` to use something
60+
else, though.
61+
- **Stage 1:** the code in your clone (for new version) is then
62+
compiled with the stage0 compiler to produce the stage1 compiler.
63+
However, it was built with an older compiler (stage0), so to
64+
optimize the stage1 compiler we go to next stage.
65+
- **Stage 2:** we rebuild our stage1 compiler with itself to produce
66+
the stage2 compiler (i.e. it builds itself) to have all the _latest
67+
optimizations_.
68+
- _(Optional)_ **Stage 3**: to sanity check of our new compiler, we
69+
can build it again with stage2 compiler which must be identical to
70+
itself, unless something has broken.
7471

7572
For hacking, often building the stage 1 compiler is enough, but for
7673
final testing and release, the stage 2 compiler is used.
@@ -80,6 +77,8 @@ It is, in particular, very useful when you're doing some kind of
8077
"type-based refactoring", like renaming a method, or changing the
8178
signature of some function.
8279

80+
<a name=command>
81+
8382
Once you've created a config.toml, you are now ready to run
8483
`x.py`. There are a lot of options here, but let's start with what is
8584
probably the best "go to" command for building a local rust:
@@ -88,27 +87,39 @@ probably the best "go to" command for building a local rust:
8887
> ./x.py build -i --stage 1 src/libstd
8988
```
9089

91-
What this command will do is the following:
90+
This may *look* like it only builds libstd, but that is not the case.
91+
What this command does is the following:
92+
93+
- Build libstd using the stage0 compiler (using incremental)
94+
- Build librustc using the stage0 compiler (using incremental)
95+
- This produces the stage1 compiler
96+
- Build libstd using the stage1 compiler (cannot use incremental)
97+
98+
This final product (stage1 compiler + libs build using that compiler)
99+
is what you need to build other rust programs.
92100

93-
- Using the beta compiler (also called stage 0), it will build the
94-
standard library and rustc from the `src` directory. The resulting
95-
compiler is called the "stage 1" compiler.
96-
- During this build, the `-i` (or `--incremental`) switch enables incremental
97-
compilation, so that if you later rebuild after editing things in
98-
`src`, you can save a bit of time.
99-
- Using this stage 1 compiler, it will build the standard library.
100-
(this is what the `src/libstd`) means.
101+
Note that the command includes the `-i` switch. This enables incremental
102+
compilation. This will be used to speed up the first two steps of the process:
103+
in particular, if you make a small change, we ought to be able to use your old
104+
results to make producing the stage1 **compiler** faster.
101105

102-
This is just a subset of the full rustc build. The **full** rustc build
103-
(what you get if you just say `./x.py build`) has quite a few more steps:
106+
Unfortunately, incremental cannot be used to speed up making the
107+
stage1 libraries. This is because incremental only works when you run
108+
the *same compiler* twice in a row. In this case, we are building a
109+
*new stage1 compiler* every time. Therefore, the old incremental
110+
results may not apply. **As a result, you will probably find that
111+
building the stage1 libstd is a bottleneck for you** -- but fear not,
112+
there is a (hacky) workaround. See [the section on "recommended
113+
workflows"](#workflow) below.
104114

105-
- Build stage1 rustc with stage0 compiler.
106-
- Build libstd with stage1 compiler (up to here is the same).
107-
- Build rustc from `src` again, this time with the stage1 compiler
108-
(this part is new).
115+
Note that this whole command just gives you a subset of the full rustc
116+
build. The **full** rustc build (what you get if you just say `./x.py
117+
build`) has quite a few more steps:
118+
119+
- Build librustc rustc with the stage1 compiler.
109120
- The resulting compiler here is called the "stage2" compiler.
110121
- Build libstd with stage2 compiler.
111-
- Build librustdoc and a bunch of other things.
122+
- Build librustdoc and a bunch of other things with the stage2 compiler.
112123

113124
<a name=toolchain></a>
114125

@@ -148,6 +159,61 @@ release: 1.25.0-dev
148159
LLVM version: 4.0
149160
```
150161

162+
<a name=workflow>
163+
164+
### Suggested workflows for faster builds of the compiler
165+
166+
There are two workflows that are useful for faster builders of the
167+
compiler.
168+
169+
**Check, check, and check again.** The first workflow, which is useful when doing
170+
simple refactorings, is to run `./x.py check` continuously. Here you
171+
are just checking that the compiler can **build**, but often that is
172+
all you need (e.g., when renaming a method). You can then run `./x.py build`
173+
when you acqtually need to run tests.
174+
175+
In fact, it is eomtimes useful to put off tests even when you are not
176+
100% sure the code will work. You can then keep building up
177+
refactoring commits and only run the tests at some later time. You can
178+
then use `git bisect` to track down **precisely** which commit caused
179+
the problem. A nice side-effect of this style is that you are left
180+
with a fairly fine-grained set of commits at the end, all of which
181+
build and pass testes. This often helps reviewing.
182+
183+
**Incremental builds with `--keep-stage`.** Sometimes just checking
184+
whether the compiler builds is not enough. A common example is that
185+
you need to add a `debug!` statement to inspect the value of some
186+
state or better understand the problem. In that case, you really need
187+
a full build. By leveraging incremental, though, you can often get
188+
these builds to complete very fast (e.g., around 30 seconds): the only
189+
catch is this requires a bit of fudging and may produce compilers that
190+
don't work (but that is easily detected and fixed).
191+
192+
The sequence of commands you want is as follows:
193+
194+
- Initial build: `./x.py build -i --stage 1 src/libstd`
195+
- As [documented above](#command), this will build a functional stage1 compiler
196+
- Subsequent builds: `./x.py build -i --stage 1 src/libstd --keep-stage 1`
197+
- Note that we added the `--keep-stage 1` flag here
198+
199+
The effect of `--keep-stage1` is that we just *assume* that the old
200+
standard library can be re-used. If you are editing the compiler, this
201+
is almost always true: you haven't changed the standard library, after
202+
all. But sometimes, it's not true: for example, if you are editing
203+
the "metadata" part of the compiler, which controls how the compiler
204+
encodes types and other states into the `rlib` files, or if you are editing
205+
things that wind up in the metadata (such as the definition of the MIR).
206+
207+
**The TL;DR is that you might get weird behavior from a compile when
208+
using `--keep-stage 1`** -- for example, strange ICEs or other
209+
panics. In that case, you should simply remove the `--keep-stage 1`
210+
from the command and rebuild. That ought to fix the problem.
211+
212+
Note: you can also use `--keep-stage 1` when running tests. Something like this:
213+
214+
- Initial test run: `./x.py test -i --stage 1 src/test/ui`
215+
- Subsequent test run: `./x.py test -i --stage 1 src/test/ui --keep-stage 1`
216+
151217
### Other x.py commands
152218

153219
Here are a few other useful x.py commands. We'll cover some of them in detail

0 commit comments

Comments
 (0)