Skip to content

Feature request: Option to use rust-analyzer-specific target directory (relative to target directory) #6007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
d4h0 opened this issue Sep 15, 2020 · 28 comments · Fixed by #15681
Labels
A-config configuration C-enhancement Category: enhancement E-medium good first issue S-actionable Someone could pick this issue up and work on it right now

Comments

@d4h0
Copy link

d4h0 commented Sep 15, 2020

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-Analyzer to use a specific directory relative to the target directory.

Edit: This comment contains a good workaround to switch Rust-Analyzer to a different Cargo profile, globally.

@matklad matklad added E-medium S-actionable Someone could pick this issue up and work on it right now labels Oct 15, 2020
@matklad
Copy link
Member

matklad commented Oct 15, 2020

Could probably be fixed by #6099 by setting CARGO_TARGET_DIR. I also wouldn't be opposed to having a dedicated option for this.

@wycats
Copy link

wycats commented Nov 5, 2020

@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?

@lnicola
Copy link
Member

lnicola commented Nov 5, 2020

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.

@wycats
Copy link

wycats commented Nov 5, 2020

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.

@gilescope
Copy link
Contributor

@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.

@lnicola
Copy link
Member

lnicola commented Jul 8, 2021

Can you set CARGO_TARGET_DIR in rust-analyzer.server.extraEnv?

@Ralith
Copy link

Ralith commented Jul 10, 2021

Difficulty presenting a consistent environment to rustc is causing RA to clobber my compile cache constantly (see #4616 (comment)). 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.

@gilescope
Copy link
Contributor

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.

@Ralith
Copy link

Ralith commented Jul 11, 2021

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.

@Lucretiel
Copy link

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.

@Veykril Veykril added the A-config configuration label May 20, 2022
@faern
Copy link

faern commented Aug 27, 2022

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.

@matklad
Copy link
Member

matklad commented Aug 29, 2022

Given the amount of 👍 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:
    /// Automatically refresh project info via `cargo metadata` on
    /// `Cargo.toml` or `.cargo/config.toml` changes.
    cargo_autoreload: bool = "true",
    /// Run build scripts (`build.rs`) for more precise code analysis.
    cargo_buildScripts_enable: bool = "true",
    /// Override the command rust-analyzer uses to run build scripts and
    /// build procedural macros. The command is required to output json
    /// and should therefore include `--message-format=json` or a similar
    /// option.
    ///
    /// By default, a cargo invocation will be constructed for the configured
    /// targets and features, with the following base command line:
    ///
    /// ```bash
    /// cargo check --quiet --workspace --message-format=json --all-targets
    /// ```
    /// .
    cargo_buildScripts_overrideCommand: Option<Vec<String>> = "null",
    /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
    /// avoid checking unnecessary things.
    cargo_buildScripts_useRustcWrapper: bool = "true",
    /// List of features to activate.
    ///
    /// Set this to `"all"` to pass `--all-features` to cargo.
    cargo_features: CargoFeatures = "[]",
    /// Whether to pass `--no-default-features` to cargo.
    cargo_noDefaultFeatures: bool = "false",
    /// Internal config for debugging, disables loading of sysroot crates.
    cargo_noSysroot: bool = "false",
    /// Compilation target override (target triple).
    cargo_target: Option<String> = "null",
    /// Unsets `#[cfg(test)]` for the specified crates.
    cargo_unsetTest: Vec<String> = "[\"core\"]",
  • where the JSON is lowered to domain model:
    pub fn cargo(&self) -> CargoConfig {
    let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| {
    if rustc_src == "discover" {
    RustcSource::Discover
    } else {
    RustcSource::Path(self.root_path.join(rustc_src))
    }
    });
    CargoConfig {
    no_default_features: self.data.cargo_noDefaultFeatures,
    all_features: matches!(self.data.cargo_features, CargoFeatures::All),
    features: match &self.data.cargo_features {
    CargoFeatures::All => vec![],
    CargoFeatures::Listed(it) => it.clone(),
    },
    target: self.data.cargo_target.clone(),
    no_sysroot: self.data.cargo_noSysroot,
    rustc_source,
    unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
    wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
    run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
    }
    }
    ,
    pub fn flycheck(&self) -> Option<FlycheckConfig> {
  • looking at the usages of FlycheckConfig and CargoConfig should 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

@Hanssen0
Copy link

Hanssen0 commented Sep 4, 2022

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

  1. Like --target-dir, it's also related to the current dir instead of the project dir.
  2. It doesn't change following the editing file.

@Tyrubias
Copy link
Contributor

Tyrubias commented Oct 24, 2022

@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?

@MrEmanuel
Copy link

MrEmanuel commented Oct 29, 2022

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?

@d4h0
Copy link
Author

d4h0 commented Oct 29, 2022

@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.

@gilescope
Copy link
Contributor

gilescope commented Nov 12, 2022 via email

@d4h0
Copy link
Author

d4h0 commented Jan 11, 2023

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.

@liamaharon
Copy link

liamaharon commented Mar 23, 2023

@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"
  ],

@Taywee
Copy link

Taywee commented Apr 24, 2023

@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.

@utkarshgupta137
Copy link

@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.

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.

@MartinKavik
Copy link

MartinKavik commented Apr 26, 2023

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.

@daxpedda
Copy link
Contributor

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"
    ]
}

@utkarshgupta137
Copy link

utkarshgupta137 commented May 1, 2023

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.

@CGMossa
Copy link

CGMossa commented Sep 23, 2023

Can someone please tell us which one works?

Tyrubias added a commit to Tyrubias/rust-analyzer that referenced this issue Sep 29, 2023
Adds a Rust Analyzer configuration option to set a custom
target directory for builds. This is a workaround for Rust Analyzer
blocking debug builds while running `cargo check`. This change
should close rust-lang#6007
Tyrubias added a commit to Tyrubias/rust-analyzer that referenced this issue Oct 1, 2023
Adds a Rust Analyzer configuration option to set a custom
target directory for builds. This is a workaround for Rust Analyzer
blocking debug builds while running `cargo check`. This change
should close rust-lang#6007
Tyrubias added a commit to Tyrubias/rust-analyzer that referenced this issue Oct 4, 2023
Adds a Rust Analyzer configuration option to set a custom
target directory for builds. This is a workaround for Rust Analyzer
blocking debug builds while running `cargo check`. This change
should close rust-lang#6007
Tyrubias added a commit to Tyrubias/rust-analyzer that referenced this issue Oct 6, 2023
Adds a Rust Analyzer configuration option to set a custom
target directory for builds. This is a workaround for Rust Analyzer
blocking debug builds while running `cargo check`. This change
should close rust-lang#6007
bors added a commit that referenced this issue Oct 9, 2023
Add config option to use `rust-analyzer` specific target dir

Adds a Rust Analyzer configuration option to set a custom target directory for builds. This is a workaround for Rust Analyzer blocking debug builds while running `cargo check`. This change should close #6007.

This is my first time contributing to this project, so any feedback regarding best practices that I'm not aware of are greatly appreciated! Thanks to all the maintainers for their hard work on this project and reviewing contributions.
@bors bors closed this as completed in aeef7b6 Oct 9, 2023
billylanchantin added a commit to elixir-explorer/explorer that referenced this issue Feb 2, 2024
billylanchantin added a commit to elixir-explorer/explorer that referenced this issue Feb 2, 2024
* add symlink

* ignore artifacts

* settings.json works way better

rust-lang/rust-analyzer#6007 (comment)

* fix EOF (hopefully)

* fix another EOF

* mention some recommended extensions
mosure added a commit to mosure/bevy_zeroverse that referenced this issue Jun 29, 2024
@tzemanovic
Copy link

this simple option works in helix:

[language-server.rust-analyzer.config.cargo]
targetDir = true

you can also set it to a relative path (the default with true is target/rust-analyzer)

@raldone01
Copy link

For vscode put the following in .vscode/settings.json:

{
  "rust-analyzer.cargo.targetDir": true,
}

@iskng
Copy link

iskng commented Dec 27, 2024

For vscode put the following in .vscode/settings.json:

{
"rust-analyzer.cargo.targetDir": true,
}

@raldone01 thank you!
before cargo check 34.98s user 2.02s system 122% cpu 30.176 total
after cargo check 2.62s user 0.60s system 84% cpu 3.803 total

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-config configuration C-enhancement Category: enhancement E-medium good first issue S-actionable Someone could pick this issue up and work on it right now
Projects
None yet
Development

Successfully merging a pull request may close this issue.