diff options
| author | bors <bors@rust-lang.org> | 2023-10-09 07:27:03 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-10-09 07:27:03 +0000 |
| commit | d646ae80c56d3be0f0566d0cf4c72e1bbbe24ed1 (patch) | |
| tree | a04ac6a46aa1c5ba586b82bf4eac499e340d5236 | |
| parent | 7e9b25bff75a24bd85521ca54fa9d01edd35ad1d (diff) | |
| parent | a39d2076db1f39e49a7c7c5365eac8a11abcdc9e (diff) | |
| download | rust-d646ae80c56d3be0f0566d0cf4c72e1bbbe24ed1.tar.gz rust-d646ae80c56d3be0f0566d0cf4c72e1bbbe24ed1.zip | |
Auto merge of #15681 - Tyrubias:custom_target_dir, r=Veykril
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.
| -rw-r--r-- | crates/flycheck/src/lib.rs | 5 | ||||
| -rw-r--r-- | crates/project-model/src/build_scripts.rs | 4 | ||||
| -rw-r--r-- | crates/project-model/src/cargo_workspace.rs | 2 | ||||
| -rw-r--r-- | crates/rust-analyzer/src/config.rs | 104 | ||||
| -rw-r--r-- | docs/user/generated_config.adoc | 10 | ||||
| -rw-r--r-- | editors/code/package.json | 15 |
6 files changed, 140 insertions, 0 deletions
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 2de719af92c..0749d91eb32 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -50,6 +50,7 @@ pub enum FlycheckConfig { extra_args: Vec<String>, extra_env: FxHashMap<String, String>, ansi_color_output: bool, + target_dir: Option<PathBuf>, }, CustomCommand { command: String, @@ -308,6 +309,7 @@ impl FlycheckActor { features, extra_env, ansi_color_output, + target_dir, } => { let mut cmd = Command::new(toolchain::cargo()); cmd.arg(command); @@ -340,6 +342,9 @@ impl FlycheckActor { cmd.arg(features.join(" ")); } } + if let Some(target_dir) = target_dir { + cmd.arg("--target-dir").arg(target_dir); + } cmd.envs(extra_env); (cmd, extra_args) } diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index fb0f3ab7d17..68cd40c040b 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -73,6 +73,10 @@ impl WorkspaceBuildScripts { cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]); cmd.args(&config.extra_args); + if let Some(target_dir) = &config.target_dir { + cmd.arg("--target-dir").arg(target_dir); + } + // --all-targets includes tests, benches and examples in addition to the // default lib and bins. This is an independent concept from the --target // flag below. diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index e47808a2cc9..ca3d6e0596c 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -96,6 +96,8 @@ pub struct CargoConfig { pub extra_env: FxHashMap<String, String>, pub invocation_strategy: InvocationStrategy, pub invocation_location: InvocationLocation, + /// Optional path to use instead of `target` when building + pub target_dir: Option<PathBuf>, } pub type Package = Idx<PackageData>; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8e780baa36d..c8df4255d96 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -480,6 +480,14 @@ config_data! { /// tests or binaries. For example, it may be `--release`. runnables_extraArgs: Vec<String> = "[]", + /// Optional path to a rust-analyzer specific target directory. + /// This prevents rust-analyzer's `cargo check` from locking the `Cargo.lock` + /// at the expense of duplicating build artifacts. + /// + /// Set to `true` to use a subdirectory of the existing target directory or + /// set to a path relative to the workspace to use that path. + rust_analyzerTargetDir: Option<TargetDirectory> = "null", + /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private /// projects, or "discover" to try to automatically find it if the `rustc-dev` component /// is installed. @@ -1263,6 +1271,7 @@ impl Config { run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(), extra_args: self.data.cargo_extraArgs.clone(), extra_env: self.data.cargo_extraEnv.clone(), + target_dir: self.target_dir_from_config(), } } @@ -1335,10 +1344,21 @@ impl Config { extra_args: self.check_extra_args(), extra_env: self.check_extra_env(), ansi_color_output: self.color_diagnostic_output(), + target_dir: self.target_dir_from_config(), }, } } + fn target_dir_from_config(&self) -> Option<PathBuf> { + self.data.rust_analyzerTargetDir.as_ref().and_then(|target_dir| match target_dir { + TargetDirectory::UseSubdirectory(yes) if *yes => { + Some(PathBuf::from("target/rust-analyzer")) + } + TargetDirectory::UseSubdirectory(_) => None, + TargetDirectory::Directory(dir) => Some(dir.clone()), + }) + } + pub fn check_on_save(&self) -> bool { self.data.checkOnSave } @@ -2037,6 +2057,14 @@ pub enum MemoryLayoutHoverRenderKindDef { Both, } +#[derive(Deserialize, Debug, Clone, PartialEq)] +#[serde(rename_all = "snake_case")] +#[serde(untagged)] +pub enum TargetDirectory { + UseSubdirectory(bool), + Directory(PathBuf), +} + macro_rules! _config_data { (struct $name:ident { $( @@ -2465,6 +2493,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json }, ], }, + "Option<TargetDirectory>" => set! { + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "string" + }, + ], + }, _ => panic!("missing entry for {ty}: {default}"), } @@ -2625,4 +2666,67 @@ mod tests { Some(AbsPathBuf::try_from(project_root().join("./server")).unwrap()) ); } + + #[test] + fn cargo_target_dir_unset() { + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); + config + .update(serde_json::json!({ + "rust": { "analyzerTargetDir": null } + })) + .unwrap(); + assert_eq!(config.data.rust_analyzerTargetDir, None); + assert!( + matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == None) + ); + } + + #[test] + fn cargo_target_dir_subdir() { + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); + config + .update(serde_json::json!({ + "rust": { "analyzerTargetDir": true } + })) + .unwrap(); + assert_eq!( + config.data.rust_analyzerTargetDir, + Some(TargetDirectory::UseSubdirectory(true)) + ); + assert!( + matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("target/rust-analyzer"))) + ); + } + + #[test] + fn cargo_target_dir_relative_dir() { + let mut config = Config::new( + AbsPathBuf::try_from(project_root()).unwrap(), + Default::default(), + vec![], + false, + ); + config + .update(serde_json::json!({ + "rust": { "analyzerTargetDir": "other_folder" } + })) + .unwrap(); + assert_eq!( + config.data.rust_analyzerTargetDir, + Some(TargetDirectory::Directory(PathBuf::from("other_folder"))) + ); + assert!( + matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("other_folder"))) + ); + } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index dec7a507574..7c76ae81bea 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -757,6 +757,16 @@ Command to be executed instead of 'cargo' for runnables. Additional arguments to be passed to cargo for runnables such as tests or binaries. For example, it may be `--release`. -- +[[rust-analyzer.rust.analyzerTargetDir]]rust-analyzer.rust.analyzerTargetDir (default: `null`):: ++ +-- +Optional path to a rust-analyzer specific target directory. +This prevents rust-analyzer's `cargo check` from locking the `Cargo.lock` +at the expense of duplicating build artifacts. + +Set to `true` to use a subdirectory of the existing target directory or +set to a path relative to the workspace to use that path. +-- [[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 554b05c46c7..fc6597a0d40 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1488,6 +1488,21 @@ "type": "string" } }, + "rust-analyzer.rust.analyzerTargetDir": { + "markdownDescription": "Optional path to a rust-analyzer specific target directory.\nThis prevents rust-analyzer's `cargo check` from locking the `Cargo.lock`\nat the expense of duplicating build artifacts.\n\nSet to `true` to use a subdirectory of the existing target directory or\nset to a path relative to the workspace to use that path.", + "default": null, + "anyOf": [ + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "string" + } + ] + }, "rust-analyzer.rustc.source": { "markdownDescription": "Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private\nprojects, or \"discover\" to try to automatically find it if the `rustc-dev` component\nis installed.\n\nAny project which uses rust-analyzer with the rustcPrivate\ncrates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.\n\nThis option does not take effect until rust-analyzer is restarted.", "default": null, |
