Overview
For non-Cargo projects,
rust-analyzer depends on either a rust-project.json
file
at the root of the project that describes its structure or on build system specific
project auto-discovery.
The rust_analyzer
rules facilitate both approaches.
rust-project.json approach
Setup
First, ensure rules_rust
is setup in your workspace. By default, rust_register_toolchains
will
ensure a rust_analyzer_toolchain is registered within the WORKSPACE.
Next, load the dependencies for the rust-project.json
generator tool:
load("@rules_rust//tools/rust_analyzer:deps.bzl", "rust_analyzer_dependencies")
rust_analyzer_dependencies()
Finally, run bazel run @rules_rust//tools/rust_analyzer:gen_rust_project
whenever dependencies change to regenerate the rust-project.json
file. It
should be added to .gitignore
because it is effectively a build artifact.
Once the rust-project.json
has been generated in the project root,
rust-analyzer can pick it up upon restart.
For users who do not use rust_register_toolchains
to register toolchains, the following can be added
to their WORKSPACE to register a rust_analyzer_toolchain
. Please make sure the Rust version used in
this toolchain matches the version used by the currently registered toolchain or the sources/documentation
will not match what's being compiled with and can lead to confusing results.
load("@rules_rust//rust:repositories.bzl", "rust_analyzer_toolchain_repository")
register_toolchains(rust_analyzer_toolchain_repository(
name = "rust_analyzer_toolchain",
# This should match the currently registered toolchain.
version = "1.63.0",
))
VSCode
To set this up using VSCode, users should first install the
rust_analyzer plugin.
With that in place, the following task can be added to the .vscode/tasks.json
file of the workspace
to ensure a rust-project.json
file is created and up to date when the editor is opened.
{
"version": "2.0.0",
"tasks": [
{
"label": "Generate rust-project.json",
"command": "bazel",
"args": [
"run",
"@rules_rust//tools/rust_analyzer:gen_rust_project"
],
"options": {
"cwd": "${workspaceFolder}"
},
"group": "build",
"problemMatcher": [],
"presentation": {
"reveal": "never",
"panel": "dedicated"
},
"runOptions": {
"runOn": "folderOpen"
}
},
]
}
Alternative vscode option (prototype)
Add the following to your bazelrc:
build --@rules_rust//rust/settings:rustc_output_diagnostics=true --output_groups=+rust_lib_rustc_output,+rust_metadata_rustc_output
Then you can use a prototype rust-analyzer plugin that automatically collects the outputs whenever you recompile.
Project auto-discovery
Setup
Auto-discovery makes rust-analyzer
behave in a Bazel project in a similar fashion to how it does
in a Cargo project. This is achieved by generating a structure similar to what rust-project.json
contains but, instead of writing that to a file, the data gets piped to rust-analyzer
directly
through stdout
. To use auto-discovery the rust-analyzer
IDE settings must be configured similar to:
"rust-analyzer": {
"workspace": {
"discoverConfig": {
"command": ["discover_bazel_rust_project.sh"],
"progressLabel": "rust_analyzer",
"filesToWatch": ["BUILD", "BUILD.bazel", "MODULE.bazel"]
}
}
}
The shell script passed to discoverConfig.command
is typically meant to wrap the bazel rule invocation,
primarily for muting stderr
(because rust-analyzer
will consider that an error has occurred if anything
is passed through stderr
) and, additionally, for specifying rule arguments. E.g:
#!/usr/bin/bash
bazel \
run \
@rules_rust//tools/rust_analyzer:discover_bazel_rust_project -- \
--bazel_startup_option=--output_base=~/ide_bazel \
--bazel_arg=--watchfs \
${1:+"$1"} 2>/dev/null
The script above also handles an optional CLI argument which gets passed when workspace splitting is enabled. The script path should be either absolute or relative to the project root.
Workspace splitting
The above configuration treats the entire project as a single workspace. However, large codebases might be
too much to handle for rust-analyzer
all at once. This can be addressed by splitting the codebase in
multiple workspaces by extending the discoverConfig.command
setting:
"rust-analyzer": {
"workspace": {
"discoverConfig": {
"command": ["discover_bazel_rust_project.sh", "{arg}"],
"progressLabel": "rust_analyzer",
"filesToWatch": ["BUILD", "BUILD.bazel", "MODULE.bazel"]
}
}
}
{arg}
acts as a placeholder that rust-analyzer
replaces with the path of the source / build file
that gets opened.
The root of the workspace will, in this configuration, be the package the crate currently being worked on
belongs to. This means that only that package and its dependencies get built and indexed by rust-analyzer
,
thus allowing for a smaller footprint.
rust-analyzer
will switch workspaces whenever an out-of-tree file gets opened, essentially indexing that
crate and its dependencies separately. A caveat of this is that dependents of the crate currently being
worked on are not indexed and won't be tracked by rust-analyzer
.
Aspects
rust_analyzer_aspect
load("@rules_rust//rust:defs.bzl", "rust_analyzer_aspect") rust_analyzer_aspect()
Annotates rust rules with RustAnalyzerInfo later used to build a rust-project.json
ASPECT ATTRIBUTES
Name | Type |
---|---|
deps | String |
proc_macro_deps | String |
crate | String |
actual | String |
proto | String |
ATTRIBUTES