Skip to content

Commit 38fa47f

Browse files
committed
Auto merge of #13290 - poliorcetics:multiple-targets, r=Veykril
Support multiple targets for checkOnSave (in conjunction with cargo 1.64.0+) This PR adds support for the ability to pass multiple `--target` flags when using `cargo` 1.64.0+. ## Questions I needed to change the type of two configurations options, but I did not plurialize the names to avoid too much churn, should I ? ## Zulip thread https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer/topic/Issue.2013282.20.28supporting.20multiple.20targets.20with.201.2E64.2B.29 ## Example To see it working, on a macOS machine: ```sh $ cd /tmp $ cargo new cargo-multiple-targets-support-ra-test $ cd !$ $ mkdir .cargo $ echo ' [build] target = [ "aarch64-apple-darwin", "x86_64-apple-darwin", ] ' > .cargo/config.toml $ echo ' fn main() { #[cfg(all(target_arch = "aarch64", target_os = "macos"))] { let a = std::fs::read_to_string("/tmp/test-read"); } #[cfg(all(target_arch = "x86_64", target_os = "macos"))] { let a = std::fs::read_to_string("/tmp/test-read"); } #[cfg(all(target_arch = "x86_64", target_os = "windows"))] { let a = std::fs::read_to_string("/tmp/test-read"); } } ' > src/main.rs # launch your favorite editor with the version of RA from this PR # # You should see warnings under the first two `let a = ...` but not the third ``` ## Screen ![Two panes of a terminal emulator, on the left pane is the main.rs file described above, with warnings for the first two let a = declaration, on the right pane is a display of the .cargo/config.toml, an ls of the current files in the directory and a call to cargo build to show the same warnings as in the editor on the left pane](https://user-images.githubusercontent.com/7951708/192122707-7a00606a-e581-4534-b9d5-b81c92694e8e.png) Helps with #13282
2 parents 2d9ed4f + 0d4737a commit 38fa47f

File tree

6 files changed

+87
-35
lines changed

6 files changed

+87
-35
lines changed

crates/flycheck/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub enum InvocationLocation {
4040
pub enum FlycheckConfig {
4141
CargoCommand {
4242
command: String,
43-
target_triple: Option<String>,
43+
target_triples: Vec<String>,
4444
all_targets: bool,
4545
no_default_features: bool,
4646
all_features: bool,
@@ -286,7 +286,7 @@ impl FlycheckActor {
286286
let (mut cmd, args) = match &self.config {
287287
FlycheckConfig::CargoCommand {
288288
command,
289-
target_triple,
289+
target_triples,
290290
no_default_features,
291291
all_targets,
292292
all_features,
@@ -300,7 +300,7 @@ impl FlycheckActor {
300300
cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
301301
.arg(self.root.join("Cargo.toml").as_os_str());
302302

303-
if let Some(target) = target_triple {
303+
for target in target_triples {
304304
cmd.args(&["--target", target.as_str()]);
305305
}
306306
if *all_targets {

crates/project-model/src/build_scripts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl WorkspaceBuildScripts {
6969
cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
7070

7171
// --all-targets includes tests, benches and examples in addition to the
72-
// default lib and bins. This is an independent concept from the --targets
72+
// default lib and bins. This is an independent concept from the --target
7373
// flag below.
7474
cmd.arg("--all-targets");
7575

crates/project-model/src/cargo_workspace.rs

+36-14
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,7 @@ impl CargoWorkspace {
270270
config: &CargoConfig,
271271
progress: &dyn Fn(String),
272272
) -> Result<cargo_metadata::Metadata> {
273-
let target = config
274-
.target
275-
.clone()
276-
.or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env))
277-
.or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env));
273+
let targets = find_list_of_build_targets(config, cargo_toml);
278274

279275
let mut meta = MetadataCommand::new();
280276
meta.cargo_path(toolchain::cargo());
@@ -294,8 +290,12 @@ impl CargoWorkspace {
294290
}
295291
meta.current_dir(current_dir.as_os_str());
296292

297-
if let Some(target) = target {
298-
meta.other_options(vec![String::from("--filter-platform"), target]);
293+
if !targets.is_empty() {
294+
let other_options: Vec<_> = targets
295+
.into_iter()
296+
.flat_map(|target| ["--filter-platform".to_string(), target])
297+
.collect();
298+
meta.other_options(other_options);
299299
}
300300

301301
// FIXME: Fetching metadata is a slow process, as it might require
@@ -469,6 +469,19 @@ impl CargoWorkspace {
469469
}
470470
}
471471

472+
fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec<String> {
473+
if let Some(target) = &config.target {
474+
return [target.into()].to_vec();
475+
}
476+
477+
let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env);
478+
if !build_targets.is_empty() {
479+
return build_targets;
480+
}
481+
482+
rustc_discover_host_triple(cargo_toml, &config.extra_env).into_iter().collect()
483+
}
484+
472485
fn rustc_discover_host_triple(
473486
cargo_toml: &ManifestPath,
474487
extra_env: &FxHashMap<String, String>,
@@ -499,20 +512,29 @@ fn rustc_discover_host_triple(
499512
fn cargo_config_build_target(
500513
cargo_toml: &ManifestPath,
501514
extra_env: &FxHashMap<String, String>,
502-
) -> Option<String> {
515+
) -> Vec<String> {
503516
let mut cargo_config = Command::new(toolchain::cargo());
504517
cargo_config.envs(extra_env);
505518
cargo_config
506519
.current_dir(cargo_toml.parent())
507520
.args(&["-Z", "unstable-options", "config", "get", "build.target"])
508521
.env("RUSTC_BOOTSTRAP", "1");
509522
// if successful we receive `build.target = "target-triple"`
523+
// or `build.target = ["<target 1>", ..]`
510524
tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
511-
match utf8_stdout(cargo_config) {
512-
Ok(stdout) => stdout
513-
.strip_prefix("build.target = \"")
514-
.and_then(|stdout| stdout.strip_suffix('"'))
515-
.map(ToOwned::to_owned),
516-
Err(_) => None,
525+
utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default()
526+
}
527+
528+
fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> {
529+
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
530+
531+
if !trimmed.starts_with('[') {
532+
return [trimmed.to_string()].to_vec();
533+
}
534+
535+
let res = serde_json::from_str(trimmed);
536+
if let Err(e) = &res {
537+
tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e);
517538
}
539+
res.unwrap_or_default()
518540
}

crates/rust-analyzer/src/config.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,11 @@ config_data! {
118118
/// This option does not take effect until rust-analyzer is restarted.
119119
cargo_sysroot: Option<String> = "\"discover\"",
120120
/// Compilation target override (target triple).
121+
// FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
122+
// than `checkOnSave_target`
121123
cargo_target: Option<String> = "null",
122124
/// Unsets `#[cfg(test)]` for the specified crates.
123-
cargo_unsetTest: Vec<String> = "[\"core\"]",
125+
cargo_unsetTest: Vec<String> = "[\"core\"]",
124126

125127
/// Check all targets and tests (`--all-targets`).
126128
checkOnSave_allTargets: bool = "true",
@@ -174,9 +176,13 @@ config_data! {
174176
/// ```
175177
/// .
176178
checkOnSave_overrideCommand: Option<Vec<String>> = "null",
177-
/// Check for a specific target. Defaults to
178-
/// `#rust-analyzer.cargo.target#`.
179-
checkOnSave_target: Option<String> = "null",
179+
/// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.
180+
///
181+
/// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g.
182+
/// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`.
183+
///
184+
/// Aliased as `"checkOnSave.targets"`.
185+
checkOnSave_target | checkOnSave_targets: CheckOnSaveTargets = "[]",
180186

181187
/// Toggles the additional completions that automatically add imports when completed.
182188
/// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
@@ -1147,11 +1153,10 @@ impl Config {
11471153
}
11481154
Some(_) | None => FlycheckConfig::CargoCommand {
11491155
command: self.data.checkOnSave_command.clone(),
1150-
target_triple: self
1151-
.data
1152-
.checkOnSave_target
1153-
.clone()
1154-
.or_else(|| self.data.cargo_target.clone()),
1156+
target_triples: match &self.data.checkOnSave_target.0[..] {
1157+
[] => self.data.cargo_target.clone().into_iter().collect(),
1158+
targets => targets.into(),
1159+
},
11551160
all_targets: self.data.checkOnSave_allTargets,
11561161
no_default_features: self
11571162
.data
@@ -1657,6 +1662,9 @@ enum InvocationStrategy {
16571662
PerWorkspace,
16581663
}
16591664

1665+
#[derive(Deserialize, Debug, Clone)]
1666+
struct CheckOnSaveTargets(#[serde(deserialize_with = "single_or_array")] Vec<String>);
1667+
16601668
#[derive(Deserialize, Debug, Clone)]
16611669
#[serde(rename_all = "snake_case")]
16621670
enum InvocationLocation {
@@ -2118,6 +2126,17 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
21182126
"The command will be executed in the project root."
21192127
],
21202128
},
2129+
"CheckOnSaveTargets" => set! {
2130+
"anyOf": [
2131+
{
2132+
"type": "string",
2133+
},
2134+
{
2135+
"type": "array",
2136+
"items": { "type": "string" }
2137+
},
2138+
],
2139+
},
21212140
_ => panic!("missing entry for {}: {}", ty, default),
21222141
}
21232142

docs/user/generated_config.adoc

+7-3
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,15 @@ cargo check --workspace --message-format=json --all-targets
190190
```
191191
.
192192
--
193-
[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`)::
193+
[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `[]`)::
194194
+
195195
--
196-
Check for a specific target. Defaults to
197-
`#rust-analyzer.cargo.target#`.
196+
Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.
197+
198+
Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g.
199+
`["aarch64-apple-darwin", "x86_64-apple-darwin"]`.
200+
201+
Aliased as `"checkOnSave.targets"`.
198202
--
199203
[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
200204
+

editors/code/package.json

+12-5
Original file line numberDiff line numberDiff line change
@@ -639,11 +639,18 @@
639639
}
640640
},
641641
"rust-analyzer.checkOnSave.target": {
642-
"markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.",
643-
"default": null,
644-
"type": [
645-
"null",
646-
"string"
642+
"markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.",
643+
"default": [],
644+
"anyOf": [
645+
{
646+
"type": "string"
647+
},
648+
{
649+
"type": "array",
650+
"items": {
651+
"type": "string"
652+
}
653+
}
647654
]
648655
},
649656
"rust-analyzer.completion.autoimport.enable": {

0 commit comments

Comments
 (0)