rust-analyzer
rust-analyzer copied to clipboard
Feature request: Option to use `rust-analyzer`-specific target directory (relative to target directory)
This would be useful to implement one of the workarounds for Rust analyzer "cargo check" blocks debug builds #4616 for people who use workspaces.
Normally, my current working directory is a specific crate, but I could also be in the workspace directory.
Because of that, if I add ["--target-dir", "/path/to/proect/target/check"] to "rust-analyzer.checkOnSave.extraArgs" I can't use a relative path (the path would be "target/check" if I'm in the workspace, or "../target/check" if I'm in a crate directory).
Workarounds would be to use an absolute path (then I have to set this config option for every project) or to create a symbolic link in every crate to the target directory of the workspace.
A better solution, IMO, would be if there was an option for Rust Analyser to use a specific directory relative to the target directory.
Could probably be fixed by #6099 by setting CARGO_TARGET_DIR. I also wouldn't be opposed to having a dedicated option for this.
@matklad out of curiosity, is there any reason that the vscode extension doesn't just default to using a directory that wouldn't conflict with command-line cargo use?
Using a different destination means that you'll get two different build directories if you also build from a terminal. In normal usage, cargo check is fast enough, so it's only an issue on the first load.
I prefer using the same directory to avoid building the project twice.
Maybe this could be solved in cargo: release and dev builds could presumably work simultaneously.
Another possible idea: Maybe rust-analyzer could support specifying a path to an additional .cargo/config.toml, which would then make it possible to configure any cargo-supported option, but only for rust-analyzer. Perhaps we could even default to adding .cargo/config.rust-analyzer.toml to the config used in cargo commands.
@lnicola think there would be pleanty of users that would sacrifice diskspace of two target dirs to stop having contention all the time between RA and command line. Being able to just check a checkbox [ ] to say please use an alternative dir would be super nice.
Can you set CARGO_TARGET_DIR in rust-analyzer.server.extraEnv?
Difficulty presenting a consistent environment to rustc is causing RA to clobber my compile cache constantly (see https://github.com/rust-analyzer/rust-analyzer/issues/4616#issuecomment-877711006). An inconsequential increase in disk use would be much, much better than having to spend ten minutes rebuilding the world every time I look at vscode funny.
Setting rust-analyser.server.extraEnv isn't as user friendly as a checkbox. You need to know that a json 'object' is a map and to use { and not [ brackets. Will trial it.
The other option btw is that at the bottom of vscode is a status bar where you can see what rust analyzer is doing - if we could click cancel on that so that it dropped the lock for now and tried again later that would allow the two to co-exist better.
Setting rust-analyser.server.extraEnv isn't as user friendly as a checkbox
It also doesn't actually seem to work reliably; maybe I'm doing something wrong, but separating target dirs would be foolproof.
In normal usage, cargo check is fast enough, so it's only an issue on the first load.
As someone working on an extremely large project, where some changes (especially to Cargo.toml) can take minutes for rust-analyzer to get through (during which cargo is blocked on the command line) I'd definitely love to see direct support for this.
This would be really helpful. On some projects I set specific RUSTFLAGS when I run some tests. For example RUSTFLAGS="--cfg loom" cargo test in a separate terminal. Since cargo is not smart enough to separate these artifacts from the ones produced by a regular cargo test/cargo check the entire world is rebuilt every time I touch RUSTFLAGS. This is OK when I don't have vscode running, but it becomes unbearable with rust-analyzer. Since RA is not aware of the different RUSTFLAGs, it competes with my terminal on who can rebuild the entire world the most times and lock the other out the most times.
I solved this for now with rust-analyser.server.extraEnv. Another cool thing would be if cargo could separate the artifacts keyed on all potential input values (RUSTFLAGS et al.) so that changes to them did not cause rebuilds.
Given the amount of :+1: here, and the relative simplicity of the issue, it's a bit surprising that this isn't fixed yet. It's not utterly trivial (nothing touching the interface visible to the user ever is), but should be relatively simple.
Tagging as good first issue.
Some relevant pointers:
- where the config JSON format is defined: https://github.com/rust-lang/rust-analyzer/blob/e8e598f6415461e7fe957eec1bee6afb55927d59/crates/rust-analyzer/src/config.rs#L66-L98
- where the JSON is lowered to domain model: https://github.com/rust-lang/rust-analyzer/blob/e8e598f6415461e7fe957eec1bee6afb55927d59/crates/rust-analyzer/src/config.rs#L979-L1002, https://github.com/rust-lang/rust-analyzer/blob/b1e9bcddc2dd83568ea5a5ed15a51ef2d1cdd89f/crates/rust-analyzer/src/config.rs#L982
- looking at the usages of
FlycheckConfigandCargoConfigshould flag all the places where we need to actually set the target-dir option.
Implementation-wise, I think I'd prefer setting --target-dir rather than CARGO_TARGET_DIR.
Also, in config we should support both rust_analyzerTargetDir: true as well as rust_analyzerTargetDir: "/some/path". The former would create a subdirectory in an existing target
My solution for this problem is wrapping the cargo executable.
/usr/local/bin/cargo:
#!/bin/sh
CARGO_PATH=/usr/bin/cargo
if test ! -z ${RUST_ANALYZER}; then
CARGO_TOML_PATH=$(${CARGO_PATH} locate-project --workspace --message-format=plain 2> /dev/null)
if test ! -z ${CARGO_TOML_PATH}; then
CARGO_TOML_DIR=$(dirname ${CARGO_TOML_PATH})
CARGO_TARGET_DIR=${CARGO_TOML_DIR}/target/analyzer ${CARGO_PATH} $@
exit
fi
fi
${CARGO_PATH} $@
And then set
"rust-analyzer.server.extraEnv": {
"RUST_ANALYZER": "1",
}
Setting CARGO_TARGET_DIR in rust-analyzer.server.extraEnv doesn't work since
- Like
--target-dir, it's also related to the current dir instead of the project dir. - It doesn't change following the editing file.
@matklad I would like to take this as my first issue if it's still necessary/relevant. To confirm, per your earlier comment, would this involve adding an extra option to the configuration to set a target directory relative to the project target directory?
Edit: I solved my problem with the vs-code setting "rust-analyzer.linkedProjects": ["apps/rust-app/Cargo.toml"]
I'm not sure I totally understand, but I think I'm having the same issue. I have a project with two apps. One rust and one svelte app. When opening the entire repo in vscode, rust-analyzer "failed to discover the workspace".
My project structure looks something like this
/my-project
README.md
.gitignore
/apps
/rust-app
/svelte-app
Am I right in thinking that I would have to open the /rust-app directory with vscode to get rust-analyzer to work?
I can't just point it at the correct child-directory?
@MrEmanuel: No, this isn't related to what is discussed here. You can turn /my-project into a Cargo Workspace, and add rust-app as a crate.
Can’t wait for the day when rust analyzer doesn’t need to shell out to cargo check.
On Sat, 29 Oct 2022 at 12:01, d4h0 @.***> wrote:
@MrEmanuel https://github.com/MrEmanuel: No, this isn't related to what is discussed here. You can turn /my-project into a Cargo Workspace https://doc.rust-lang.org/cargo/reference/workspaces.html, and add rust-app as a crate.
— Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust-analyzer/issues/6007#issuecomment-1295803261, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGEJCHHNWHD2KGRLN5R7QDWFT7ZRANCNFSM4RNDL4BA . You are receiving this because you commented.Message ID: @.***>
I think I found good workaround that wasn't mentioned above.
Step 1: Create a global Cargo profile in Cargo's config file.
(Note: Not in the project Cargo.toml file, in Cargo's global config file. You can add the profile to Cargo.toml, but then you have to add the profile to every project manually).
On Linux, edit $HOME/.cargo/config.toml, and add the following:
[profile.rust-analyzer]
inherits = "dev"
This creates a new Cargo profile that has the same values as the default dev profile (i.e., Debug mode), but uses a different directory in the project/workspace target directory (i.e., rust-analyzer).
Step 2: Tell Rust-Analyzer to use this new rust-analyzer profile, by providing the rust-analyzer.checkOnSave.extraArgs option.
How to do that depends on your editor.
For Helix you do it simply by adding the following code to your languages.toml file (on Linux at $HOME/.config/helix/languages.toml. You also can add it to a languages.toml file local to your project):
[[language]]
name = "rust"
config = {checkOnSave = {extraArgs = ["--profile", "rust-analyzer"]}}
Now Rust-Analyzer will always execute cargo check with the rust-analyzer profile, which will not compete with other Cargo instances.
@d4h0 's solution worked for me in VSCode with a minor tweak.
Instead of setting the profile on the checkOnSave.extraArgs I set it on cargo.extraArgs, otherwise rust-analyzer used target/debug when the editor first opened, and only switched to using the new profile on later saves.
In my settings.json:
"rust-analyzer.cargo.extraArgs": [
"--profile",
"rust-analyzer"
],
@liamaharon That doesn't seem to work for me (using the Helix editor). The rust-analyzer profile is not used for cargo check unless I put it in check.extraArgs (or checkOnSave.extraArgs). For now, I'm going to keep it in both to be safe.
@liamaharon That doesn't seem to work for me (using the Helix editor). The
rust-analyzerprofile is not used forcargo checkunless I put it incheck.extraArgs(orcheckOnSave.extraArgs). For now, I'm going to keep it in both to be safe.
Using NeoVim, adding it to both causes an error for me, saying that the arg can't be repeated. It shouldn't depend on the editor, so not sure what's up.
Just fyi I use this code in VS Code:
{
"rust-analyzer.cargo.extraEnv": {
"CARGO_PROFILE_RUST_ANALYZER_INHERITS": "dev"
},
"rust-analyzer.cargo.extraArgs": [
"--profile",
"rust-analyzer"
]
}
No need to create a global cargo config.
I've been using this quite successfully too:
{
"rust-analyzer.server.extraEnv": {
"CARGO_TARGET_DIR": "target/analyzer"
},
"rust-analyzer.check.extraArgs": [
"--target-dir=target/analyzer"
]
}
Updating from 2023-04-24 to 2023-05-01 broke proc macros for me as the cargo.extraArgs are now getting passed to the cargo metadata call. I had to move the arguments back to check.extraArgs, but now debug is being used until I save. Using target-dir doesn't work either.
Can someone please tell us which one works?