building/suggested: Add instructions for Emacs & Helix (#2080)

Co-authored-by: 许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>
This commit is contained in:
Kajetan Puchalski 2024-09-28 13:09:48 +01:00 committed by GitHub
parent de2f32e59c
commit 34a13c2e52
1 changed files with 164 additions and 131 deletions

View File

@ -1,46 +1,53 @@
# Suggested Workflows # Suggested Workflows
The full bootstrapping process takes quite a while. Here are some suggestions The full bootstrapping process takes quite a while. Here are some suggestions to
to make your life easier. make your life easier.
<!-- toc --> <!-- toc -->
## Installing a pre-push hook ## Installing a pre-push hook
CI will automatically fail your build if it doesn't pass `tidy`, our CI will automatically fail your build if it doesn't pass `tidy`, our internal
internal tool for ensuring code quality. If you'd like, you can install a tool for ensuring code quality. If you'd like, you can install a [Git
[Git hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) that will
that will automatically run `./x test tidy` on each push, to ensure automatically run `./x test tidy` on each push, to ensure your code is up to
your code is up to par. If the hook fails then run `./x test tidy --bless` par. If the hook fails then run `./x test tidy --bless` and commit the changes.
and commit the changes. If you decide later that the pre-push behavior is If you decide later that the pre-push behavior is undesirable, you can delete
undesirable, you can delete the `pre-push` file in `.git/hooks`. the `pre-push` file in `.git/hooks`.
A prebuilt git hook lives at [`src/etc/pre-push.sh`](https://github.com/rust-lang/rust/blob/master/src/etc/pre-push.sh) which can be copied into your `.git/hooks` folder as `pre-push` (without the `.sh` extension!). A prebuilt git hook lives at
[`src/etc/pre-push.sh`](https://github.com/rust-lang/rust/blob/master/src/etc/pre-push.sh)
which can be copied into your `.git/hooks` folder as `pre-push` (without the
`.sh` extension!).
You can also install the hook as a step of running `./x setup`! You can also install the hook as a step of running `./x setup`!
## Configuring `rust-analyzer` for `rustc` ## Configuring `rust-analyzer` for `rustc`
### Project-local rust-analyzer setup
`rust-analyzer` can help you check and format your code whenever you save a
file. By default, `rust-analyzer` runs the `cargo check` and `rustfmt` commands,
but you can override these commands to use more adapted versions of these tools
when hacking on `rustc`. With custom setup, `rust-analyzer` can use `./x check`
to check the sources, and the stage 0 rustfmt to format them.
The default `rust-analyzer.check.overrideCommand` command line will check all
the crates and tools in the repository. If you are working on a specific part,
you can override the command to only check the part you are working on to save
checking time. For example, if you are working on the compiler, you can override
the command to `x check compiler --json-output` to only check the compiler part.
You can run `x check --help --verbose` to see the available parts.
If you have enough free disk space and you would like to be able to run `x`
commands while rust-analyzer runs in the background, you can also add
`--build-dir build-rust-analyzer` to the `overrideCommand` to avoid x locking.
### Visual Studio Code ### Visual Studio Code
`rust-analyzer` can help you check and format your code whenever you save Running `./x setup vscode` will prompt you to create a `.vscode/settings.json`
a file. By default, `rust-analyzer` runs the `cargo check` and `rustfmt` file which will configure Visual Studio code. The recommended `rust-analyzer`
commands, but you can override these commands to use more adapted versions settings live at [`src/etc/rust_analyzer_settings.json`].
of these tools when hacking on `rustc`. For example, `x setup vscode` will prompt
you to create a `.vscode/settings.json` file which will configure Visual Studio code.
This will ask `rust-analyzer` to use `./x check` to check the sources, and the
stage 0 rustfmt to format them.
The recommended `rust-analyzer` settings live at [`src/etc/rust_analyzer_settings.json`].
The default `rust-analyzer.check.overrideCommand` command line will check all the crates and tools
in the repository. If you are working on a specific part, you can override the command to only
check the part you are working on to save checking time. For example, if you are working on
the compiler, you can override the command to `x check compiler --json-output` to only
check the compiler part. You can run `x check --help --verbose` to see the available parts.
If you have enough free disk space and you would like to be able to run `x` commands while
rust-analyzer runs in the background, you can also add `--build-dir build-rust-analyzer` to the
`overrideCommand` to avoid x locking.
If running `./x check` on save is inconvenient, in VS Code you can use a [Build If running `./x check` on save is inconvenient, in VS Code you can use a [Build
Task] instead: Task] instead:
@ -67,62 +74,87 @@ Task] instead:
### Neovim ### Neovim
For Neovim users there are several options for configuring for rustc. The easiest way is by using For Neovim users there are several options for configuring for rustc. The
[neoconf.nvim](https://github.com/folke/neoconf.nvim/), which allows for project-local easiest way is by using [neoconf.nvim](https://github.com/folke/neoconf.nvim/),
configuration files with the native LSP. The steps for how to use it are below. which allows for project-local configuration files with the native LSP. The
Note that they require rust-analyzer to already be configured with Neovim. steps for how to use it are below. Note that they require rust-analyzer to
Steps for this can be [found here](https://rust-analyzer.github.io/manual.html#nvim-lsp). already be configured with Neovim. Steps for this can be [found
here](https://rust-analyzer.github.io/manual.html#nvim-lsp).
1. First install the plugin. This can be done by following the steps in the README. 1. First install the plugin. This can be done by following the steps in the
2. Run `x setup`, which will have a prompt for it to create a `.vscode/settings.json` file. README.
`neoconf` is able to read and update rust-analyzer settings automatically when the project is 2. Run `x setup`, which will have a prompt for it to create a
opened when this file is detected. `.vscode/settings.json` file. `neoconf` is able to read and update
rust-analyzer settings automatically when the project is opened when this
file is detected.
If you're running `coc.nvim`, If you're running `coc.nvim`, you can use `:CocLocalConfig` to create a
you can use `:CocLocalConfig` to create a `.vim/coc-settings.json`, `.vim/coc-settings.json`, and copy the settings from
and copy the settings from [`src/etc/rust_analyzer_settings.json`]. [`src/etc/rust_analyzer_settings.json`].
Another way is without a plugin, and creating your own logic in your configuration. To do this you Another way is without a plugin, and creating your own logic in your
must translate the JSON to Lua yourself. The translation is 1:1 and fairly straight-forward. It configuration. To do this you must translate the JSON to Lua yourself. The
must be put in the `["rust-analyzer"]` key of the setup table, which is translation is 1:1 and fairly straight-forward. It must be put in the
[shown here](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#rust_analyzer). `["rust-analyzer"]` key of the setup table, which is [shown
here](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#rust_analyzer).
If you would like to use the build task that is described above, you may either make your own If you would like to use the build task that is described above, you may either
command in your config, or you can install a plugin such as make your own command in your config, or you can install a plugin such as
[overseer.nvim](https://github.com/stevearc/overseer.nvim) that can [read VSCode's `task.json` [overseer.nvim](https://github.com/stevearc/overseer.nvim) that can [read
files](https://github.com/stevearc/overseer.nvim/blob/master/doc/guides.md#vs-code-tasks), and VSCode's `task.json`
follow the same instructions as above. files](https://github.com/stevearc/overseer.nvim/blob/master/doc/guides.md#vs-code-tasks),
and follow the same instructions as above.
### Emacs
Emacs provides support for rust-analyzer with project-local configuration
through [Eglot](https://www.gnu.org/software/emacs/manual/html_node/eglot/).
Steps for setting up Eglot with rust-analyzer can be [found
here](https://rust-analyzer.github.io/manual.html#eglot).
Having set up Emacs & Eglot for Rust development in general, you can use the
configuration for rustc provided in [`src/etc/rust_analyzer_eglot.el`].
Simply copy the provided file to `.dir-locals.el` in the project root directory.
For more information on project-specific Eglot configuration, consult [the
manual](https://www.gnu.org/software/emacs/manual/html_node/eglot/Project_002dspecific-configuration.html).
### Helix
Helix comes with built-in LSP and rust-analyzer support.
It can be configured through `languages.toml`, as described
[here](https://docs.helix-editor.com/languages.html).
You can use the configuration for rustc provided in
[`src/etc/rust_analyzer_helix.toml`].
Simply copy the provided file to `.helix/languages.toml` in the project root
directory.
## Check, check, and check again ## Check, check, and check again
When doing simple refactorings, it can be useful to run `./x check` When doing simple refactorings, it can be useful to run `./x check`
continuously. If you set up `rust-analyzer` as described above, this will continuously. If you set up `rust-analyzer` as described above, this will be
be done for you every time you save a file. Here you are just checking that done for you every time you save a file. Here you are just checking that the
the compiler can **build**, but often that is all you need (e.g., when renaming a compiler can **build**, but often that is all you need (e.g., when renaming a
method). You can then run `./x build` when you actually need to method). You can then run `./x build` when you actually need to run tests.
run tests.
In fact, it is sometimes useful to put off tests even when you are not In fact, it is sometimes useful to put off tests even when you are not 100% sure
100% sure the code will work. You can then keep building up the code will work. You can then keep building up refactoring commits and only
refactoring commits and only run the tests at some later time. You can run the tests at some later time. You can then use `git bisect` to track down
then use `git bisect` to track down **precisely** which commit caused **precisely** which commit caused the problem. A nice side-effect of this style
the problem. A nice side-effect of this style is that you are left is that you are left with a fairly fine-grained set of commits at the end, all
with a fairly fine-grained set of commits at the end, all of which of which build and pass tests. This often helps reviewing.
build and pass tests. This often helps reviewing.
## `x suggest` ## `x suggest`
The `x suggest` subcommand suggests (and runs) a subset of the extensive The `x suggest` subcommand suggests (and runs) a subset of the extensive
`rust-lang/rust` tests based on files you have changed. This is especially useful `rust-lang/rust` tests based on files you have changed. This is especially
for new contributors who have not mastered the arcane `x` flags yet and more useful for new contributors who have not mastered the arcane `x` flags yet and
experienced contributors as a shorthand for reducing mental effort. In all cases more experienced contributors as a shorthand for reducing mental effort. In all
it is useful not to run the full tests (which can take on the order of tens of cases it is useful not to run the full tests (which can take on the order of
minutes) and just run a subset which are relevant to your changes. For example, tens of minutes) and just run a subset which are relevant to your changes. For
running `tidy` and `linkchecker` is useful when editing Markdown files, whereas UI example, running `tidy` and `linkchecker` is useful when editing Markdown files,
tests are much less likely to be helpful. While `x suggest` is a useful tool, it whereas UI tests are much less likely to be helpful. While `x suggest` is a
does not guarantee perfect coverage (just as PR CI isn't a substitute for bors). useful tool, it does not guarantee perfect coverage (just as PR CI isn't a
See the [dedicated chapter](../tests/suggest-tests.md) for more information and substitute for bors). See the [dedicated chapter](../tests/suggest-tests.md) for
contribution instructions. more information and contribution instructions.
Please note that `x suggest` is in a beta state currently and the tests that it Please note that `x suggest` is in a beta state currently and the tests that it
will suggest are limited. will suggest are limited.
@ -137,12 +169,14 @@ cd <path to rustc repo>
rustup override set nightly rustup override set nightly
``` ```
after [installing a nightly toolchain] with `rustup`. Don't forget to do this for all after [installing a nightly toolchain] with `rustup`. Don't forget to do this
directories you have [setup a worktree for]. You may need to use the pinned for all directories you have [setup a worktree for]. You may need to use the
nightly version from `src/stage0`, but often the normal `nightly` channel will work. pinned nightly version from `src/stage0`, but often the normal `nightly` channel
will work.
**Note** see [the section on vscode] for how to configure it with this real rustfmt `x` uses, **Note** see [the section on vscode] for how to configure it with this real
and [the section on rustup] for how to setup `rustup` toolchain for your bootstrapped compiler rustfmt `x` uses, and [the section on rustup] for how to setup `rustup`
toolchain for your bootstrapped compiler
**Note** This does _not_ allow you to build `rustc` with cargo directly. You **Note** This does _not_ allow you to build `rustc` with cargo directly. You
still have to use `x` to work on the compiler or standard library, this just still have to use `x` to work on the compiler or standard library, this just
@ -155,42 +189,38 @@ lets you use `cargo fmt`.
## Faster builds with `--keep-stage`. ## Faster builds with `--keep-stage`.
Sometimes just checking Sometimes just checking whether the compiler builds is not enough. A common
whether the compiler builds is not enough. A common example is that example is that you need to add a `debug!` statement to inspect the value of
you need to add a `debug!` statement to inspect the value of some some state or better understand the problem. In that case, you don't really need
state or better understand the problem. In that case, you don't really need
a full build. By bypassing bootstrap's cache invalidation, you can often get a full build. By bypassing bootstrap's cache invalidation, you can often get
these builds to complete very fast (e.g., around 30 seconds). The only these builds to complete very fast (e.g., around 30 seconds). The only catch is
catch is this requires a bit of fudging and may produce compilers that this requires a bit of fudging and may produce compilers that don't work (but
don't work (but that is easily detected and fixed). that is easily detected and fixed).
The sequence of commands you want is as follows: The sequence of commands you want is as follows:
- Initial build: `./x build library` - Initial build: `./x build library`
- As [documented previously], this will build a functional - As [documented previously], this will build a functional stage1 compiler as
stage1 compiler as part of running all stage0 commands (which include part of running all stage0 commands (which include building a `std`
building a `std` compatible with the stage1 compiler) as well as the compatible with the stage1 compiler) as well as the first few steps of the
first few steps of the "stage 1 actions" up to "stage1 (sysroot stage1) "stage 1 actions" up to "stage1 (sysroot stage1) builds std".
builds std".
- Subsequent builds: `./x build library --keep-stage 1` - Subsequent builds: `./x build library --keep-stage 1`
- Note that we added the `--keep-stage 1` flag here - Note that we added the `--keep-stage 1` flag here
[documented previously]: ./how-to-build-and-run.md#building-the-compiler [documented previously]: ./how-to-build-and-run.md#building-the-compiler
As mentioned, the effect of `--keep-stage 1` is that we just _assume_ that the As mentioned, the effect of `--keep-stage 1` is that we just _assume_ that the
old standard library can be re-used. If you are editing the compiler, this old standard library can be re-used. If you are editing the compiler, this is
is almost always true: you haven't changed the standard library, after almost always true: you haven't changed the standard library, after all. But
all. But sometimes, it's not true: for example, if you are editing sometimes, it's not true: for example, if you are editing the "metadata" part of
the "metadata" part of the compiler, which controls how the compiler the compiler, which controls how the compiler encodes types and other states
encodes types and other states into the `rlib` files, or if you are into the `rlib` files, or if you are editing things that wind up in the metadata
editing things that wind up in the metadata (such as the definition of (such as the definition of the MIR).
the MIR).
**The TL;DR is that you might get weird behavior from a compile when **The TL;DR is that you might get weird behavior from a compile when using
using `--keep-stage 1`** -- for example, strange `--keep-stage 1`** -- for example, strange [ICEs](../appendix/glossary.html#ice)
[ICEs](../appendix/glossary.html#ice) or other panics. In that case, you or other panics. In that case, you should simply remove the `--keep-stage 1`
should simply remove the `--keep-stage 1` from the command and from the command and rebuild. That ought to fix the problem.
rebuild. That ought to fix the problem.
You can also use `--keep-stage 1` when running tests. Something like this: You can also use `--keep-stage 1` when running tests. Something like this:
@ -199,24 +229,24 @@ You can also use `--keep-stage 1` when running tests. Something like this:
## Using incremental compilation ## Using incremental compilation
You can further enable the `--incremental` flag to save additional You can further enable the `--incremental` flag to save additional time in
time in subsequent rebuilds: subsequent rebuilds:
```bash ```bash
./x test tests/ui --incremental --test-args issue-1234 ./x test tests/ui --incremental --test-args issue-1234
``` ```
If you don't want to include the flag with every command, you can If you don't want to include the flag with every command, you can enable it in
enable it in the `config.toml`: the `config.toml`:
```toml ```toml
[rust] [rust]
incremental = true incremental = true
``` ```
Note that incremental compilation will use more disk space than usual. Note that incremental compilation will use more disk space than usual. If disk
If disk space is a concern for you, you might want to check the size space is a concern for you, you might want to check the size of the `build`
of the `build` directory from time to time. directory from time to time.
## Fine-tuning optimizations ## Fine-tuning optimizations
@ -238,23 +268,23 @@ opt-level = 0
## Working on multiple branches at the same time ## Working on multiple branches at the same time
Working on multiple branches in parallel can be a little annoying, since Working on multiple branches in parallel can be a little annoying, since
building the compiler on one branch will cause the old build and the building the compiler on one branch will cause the old build and the incremental
incremental compilation cache to be overwritten. One solution would be compilation cache to be overwritten. One solution would be to have multiple
to have multiple clones of the repository, but that would mean storing the clones of the repository, but that would mean storing the Git metadata multiple
Git metadata multiple times, and having to update each clone individually. times, and having to update each clone individually.
Fortunately, Git has a better solution called [worktrees]. This lets you Fortunately, Git has a better solution called [worktrees]. This lets you create
create multiple "working trees", which all share the same Git database. multiple "working trees", which all share the same Git database. Moreover,
Moreover, because all of the worktrees share the same object database, because all of the worktrees share the same object database, if you update a
if you update a branch (e.g. master) in any of them, you can use the new branch (e.g. master) in any of them, you can use the new commits from any of the
commits from any of the worktrees. One caveat, though, is that submodules worktrees. One caveat, though, is that submodules do not get shared. They will
do not get shared. They will still be cloned multiple times. still be cloned multiple times.
[worktrees]: https://git-scm.com/docs/git-worktree [worktrees]: https://git-scm.com/docs/git-worktree
Given you are inside the root directory for your Rust repository, you can Given you are inside the root directory for your Rust repository, you can create
create a "linked working tree" in a new "rust2" directory by running a "linked working tree" in a new "rust2" directory by running the following
the following command: command:
```bash ```bash
git worktree add ../rust2 git worktree add ../rust2
@ -266,8 +296,8 @@ Creating a new worktree for a new branch based on `master` looks like:
git worktree add -b my-feature ../rust2 master git worktree add -b my-feature ../rust2 master
``` ```
You can then use that rust2 folder as a separate workspace for modifying You can then use that rust2 folder as a separate workspace for modifying and
and building `rustc`! building `rustc`!
## Using nix-shell ## Using nix-shell
@ -293,9 +323,9 @@ pkgs.mkShell {
``` ```
Note that when using nix on a not-NixOS distribution, it may be necessary to set Note that when using nix on a not-NixOS distribution, it may be necessary to set
**`patch-binaries-for-nix = true` in `config.toml`**. **`patch-binaries-for-nix = true` in `config.toml`**. Bootstrap tries to detect
Bootstrap tries to detect whether it's running in nix and enable patching automatically, whether it's running in nix and enable patching automatically, but this
but this detection can have false negatives. detection can have false negatives.
You can also use your nix shell to manage `config.toml`: You can also use your nix shell to manage `config.toml`:
@ -313,12 +343,15 @@ pkgs.mkShell {
## Shell Completions ## Shell Completions
If you use Bash, Fish or PowerShell, you can find automatically-generated shell completion scripts for `x.py` in [`src/etc/completions`](https://github.com/rust-lang/rust/tree/master/src/etc/completions). If you use Bash, Fish or PowerShell, you can find automatically-generated shell
Zsh support will also be included once issues with [`clap_complete`](https://crates.io/crates/clap_complete) have been resolved. completion scripts for `x.py` in
[`src/etc/completions`](https://github.com/rust-lang/rust/tree/master/src/etc/completions).
Zsh support will also be included once issues with
[`clap_complete`](https://crates.io/crates/clap_complete) have been resolved.
You can use `source ./src/etc/completions/x.py.<extension>` You can use `source ./src/etc/completions/x.py.<extension>` to load completions
to load completions for your shell of choice, for your shell of choice, or `& .\src\etc\completions\x.py.ps1` for PowerShell.
or `& .\src\etc\completions\x.py.ps1` for PowerShell. Adding this to your shell's startup script (e.g. `.bashrc`) will automatically
Adding this to your shell's startup script (e.g. `.bashrc`) will automatically load this completion. load this completion.
[`src/etc/rust_analyzer_settings.json`]: https://github.com/rust-lang/rust/blob/master/src/etc/rust_analyzer_settings.json [`src/etc/rust_analyzer_settings.json`]: https://github.com/rust-lang/rust/blob/master/src/etc/rust_analyzer_settings.json