Skip to content

Commit d646ae8

Browse files
committed
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.
2 parents 7e9b25b + a39d207 commit d646ae8

File tree

6 files changed

+140
-0
lines changed

6 files changed

+140
-0
lines changed

crates/flycheck/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub enum FlycheckConfig {
5050
extra_args: Vec<String>,
5151
extra_env: FxHashMap<String, String>,
5252
ansi_color_output: bool,
53+
target_dir: Option<PathBuf>,
5354
},
5455
CustomCommand {
5556
command: String,
@@ -308,6 +309,7 @@ impl FlycheckActor {
308309
features,
309310
extra_env,
310311
ansi_color_output,
312+
target_dir,
311313
} => {
312314
let mut cmd = Command::new(toolchain::cargo());
313315
cmd.arg(command);
@@ -340,6 +342,9 @@ impl FlycheckActor {
340342
cmd.arg(features.join(" "));
341343
}
342344
}
345+
if let Some(target_dir) = target_dir {
346+
cmd.arg("--target-dir").arg(target_dir);
347+
}
343348
cmd.envs(extra_env);
344349
(cmd, extra_args)
345350
}

crates/project-model/src/build_scripts.rs

+4
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ impl WorkspaceBuildScripts {
7373
cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]);
7474
cmd.args(&config.extra_args);
7575

76+
if let Some(target_dir) = &config.target_dir {
77+
cmd.arg("--target-dir").arg(target_dir);
78+
}
79+
7680
// --all-targets includes tests, benches and examples in addition to the
7781
// default lib and bins. This is an independent concept from the --target
7882
// flag below.

crates/project-model/src/cargo_workspace.rs

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ pub struct CargoConfig {
9696
pub extra_env: FxHashMap<String, String>,
9797
pub invocation_strategy: InvocationStrategy,
9898
pub invocation_location: InvocationLocation,
99+
/// Optional path to use instead of `target` when building
100+
pub target_dir: Option<PathBuf>,
99101
}
100102

101103
pub type Package = Idx<PackageData>;

crates/rust-analyzer/src/config.rs

+104
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,14 @@ config_data! {
480480
/// tests or binaries. For example, it may be `--release`.
481481
runnables_extraArgs: Vec<String> = "[]",
482482

483+
/// Optional path to a rust-analyzer specific target directory.
484+
/// This prevents rust-analyzer's `cargo check` from locking the `Cargo.lock`
485+
/// at the expense of duplicating build artifacts.
486+
///
487+
/// Set to `true` to use a subdirectory of the existing target directory or
488+
/// set to a path relative to the workspace to use that path.
489+
rust_analyzerTargetDir: Option<TargetDirectory> = "null",
490+
483491
/// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
484492
/// projects, or "discover" to try to automatically find it if the `rustc-dev` component
485493
/// is installed.
@@ -1263,6 +1271,7 @@ impl Config {
12631271
run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
12641272
extra_args: self.data.cargo_extraArgs.clone(),
12651273
extra_env: self.data.cargo_extraEnv.clone(),
1274+
target_dir: self.target_dir_from_config(),
12661275
}
12671276
}
12681277

@@ -1335,10 +1344,21 @@ impl Config {
13351344
extra_args: self.check_extra_args(),
13361345
extra_env: self.check_extra_env(),
13371346
ansi_color_output: self.color_diagnostic_output(),
1347+
target_dir: self.target_dir_from_config(),
13381348
},
13391349
}
13401350
}
13411351

1352+
fn target_dir_from_config(&self) -> Option<PathBuf> {
1353+
self.data.rust_analyzerTargetDir.as_ref().and_then(|target_dir| match target_dir {
1354+
TargetDirectory::UseSubdirectory(yes) if *yes => {
1355+
Some(PathBuf::from("target/rust-analyzer"))
1356+
}
1357+
TargetDirectory::UseSubdirectory(_) => None,
1358+
TargetDirectory::Directory(dir) => Some(dir.clone()),
1359+
})
1360+
}
1361+
13421362
pub fn check_on_save(&self) -> bool {
13431363
self.data.checkOnSave
13441364
}
@@ -2037,6 +2057,14 @@ pub enum MemoryLayoutHoverRenderKindDef {
20372057
Both,
20382058
}
20392059

2060+
#[derive(Deserialize, Debug, Clone, PartialEq)]
2061+
#[serde(rename_all = "snake_case")]
2062+
#[serde(untagged)]
2063+
pub enum TargetDirectory {
2064+
UseSubdirectory(bool),
2065+
Directory(PathBuf),
2066+
}
2067+
20402068
macro_rules! _config_data {
20412069
(struct $name:ident {
20422070
$(
@@ -2465,6 +2493,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
24652493
},
24662494
],
24672495
},
2496+
"Option<TargetDirectory>" => set! {
2497+
"anyOf": [
2498+
{
2499+
"type": "null"
2500+
},
2501+
{
2502+
"type": "boolean"
2503+
},
2504+
{
2505+
"type": "string"
2506+
},
2507+
],
2508+
},
24682509
_ => panic!("missing entry for {ty}: {default}"),
24692510
}
24702511

@@ -2625,4 +2666,67 @@ mod tests {
26252666
Some(AbsPathBuf::try_from(project_root().join("./server")).unwrap())
26262667
);
26272668
}
2669+
2670+
#[test]
2671+
fn cargo_target_dir_unset() {
2672+
let mut config = Config::new(
2673+
AbsPathBuf::try_from(project_root()).unwrap(),
2674+
Default::default(),
2675+
vec![],
2676+
false,
2677+
);
2678+
config
2679+
.update(serde_json::json!({
2680+
"rust": { "analyzerTargetDir": null }
2681+
}))
2682+
.unwrap();
2683+
assert_eq!(config.data.rust_analyzerTargetDir, None);
2684+
assert!(
2685+
matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == None)
2686+
);
2687+
}
2688+
2689+
#[test]
2690+
fn cargo_target_dir_subdir() {
2691+
let mut config = Config::new(
2692+
AbsPathBuf::try_from(project_root()).unwrap(),
2693+
Default::default(),
2694+
vec![],
2695+
false,
2696+
);
2697+
config
2698+
.update(serde_json::json!({
2699+
"rust": { "analyzerTargetDir": true }
2700+
}))
2701+
.unwrap();
2702+
assert_eq!(
2703+
config.data.rust_analyzerTargetDir,
2704+
Some(TargetDirectory::UseSubdirectory(true))
2705+
);
2706+
assert!(
2707+
matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("target/rust-analyzer")))
2708+
);
2709+
}
2710+
2711+
#[test]
2712+
fn cargo_target_dir_relative_dir() {
2713+
let mut config = Config::new(
2714+
AbsPathBuf::try_from(project_root()).unwrap(),
2715+
Default::default(),
2716+
vec![],
2717+
false,
2718+
);
2719+
config
2720+
.update(serde_json::json!({
2721+
"rust": { "analyzerTargetDir": "other_folder" }
2722+
}))
2723+
.unwrap();
2724+
assert_eq!(
2725+
config.data.rust_analyzerTargetDir,
2726+
Some(TargetDirectory::Directory(PathBuf::from("other_folder")))
2727+
);
2728+
assert!(
2729+
matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(PathBuf::from("other_folder")))
2730+
);
2731+
}
26282732
}

docs/user/generated_config.adoc

+10
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,16 @@ Command to be executed instead of 'cargo' for runnables.
757757
Additional arguments to be passed to cargo for runnables such as
758758
tests or binaries. For example, it may be `--release`.
759759
--
760+
[[rust-analyzer.rust.analyzerTargetDir]]rust-analyzer.rust.analyzerTargetDir (default: `null`)::
761+
+
762+
--
763+
Optional path to a rust-analyzer specific target directory.
764+
This prevents rust-analyzer's `cargo check` from locking the `Cargo.lock`
765+
at the expense of duplicating build artifacts.
766+
767+
Set to `true` to use a subdirectory of the existing target directory or
768+
set to a path relative to the workspace to use that path.
769+
--
760770
[[rust-analyzer.rustc.source]]rust-analyzer.rustc.source (default: `null`)::
761771
+
762772
--

editors/code/package.json

+15
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,21 @@
14881488
"type": "string"
14891489
}
14901490
},
1491+
"rust-analyzer.rust.analyzerTargetDir": {
1492+
"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.",
1493+
"default": null,
1494+
"anyOf": [
1495+
{
1496+
"type": "null"
1497+
},
1498+
{
1499+
"type": "boolean"
1500+
},
1501+
{
1502+
"type": "string"
1503+
}
1504+
]
1505+
},
14911506
"rust-analyzer.rustc.source": {
14921507
"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.",
14931508
"default": null,

0 commit comments

Comments
 (0)