Skip to content

Commit 9e9bc54

Browse files
committed
feat: Support passing multiple targets to cargo (for Rust 1.64.0+)
1 parent 499c6f6 commit 9e9bc54

File tree

10 files changed

+95
-68
lines changed

10 files changed

+95
-68
lines changed

crates/flycheck/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub use cargo_metadata::diagnostic::{
2525
pub enum FlycheckConfig {
2626
CargoCommand {
2727
command: String,
28-
target_triple: Option<String>,
28+
target_triples: Vec<String>,
2929
all_targets: bool,
3030
no_default_features: bool,
3131
all_features: bool,
@@ -253,7 +253,7 @@ impl FlycheckActor {
253253
let mut cmd = match &self.config {
254254
FlycheckConfig::CargoCommand {
255255
command,
256-
target_triple,
256+
target_triples,
257257
no_default_features,
258258
all_targets,
259259
all_features,
@@ -267,7 +267,7 @@ impl FlycheckActor {
267267
cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
268268
.arg(self.workspace_root.join("Cargo.toml").as_os_str());
269269

270-
if let Some(target) = target_triple {
270+
for target in target_triples {
271271
cmd.args(&["--target", target.as_str()]);
272272
}
273273
if *all_targets {

crates/project-model/src/build_scripts.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ impl WorkspaceBuildScripts {
5252
cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
5353

5454
// --all-targets includes tests, benches and examples in addition to the
55-
// default lib and bins. This is an independent concept from the --targets
55+
// default lib and bins. This is an independent concept from the --target
5656
// flag below.
5757
cmd.arg("--all-targets");
5858

59-
if let Some(target) = &config.target {
60-
cmd.args(&["--target", target]);
59+
for target in &config.targets {
60+
cmd.args(&["--target", target.as_str()]);
6161
}
6262

6363
match &config.features {

crates/project-model/src/cargo_workspace.rs

+42-20
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ impl Default for CargoFeatures {
9292
pub struct CargoConfig {
9393
/// List of features to activate.
9494
pub features: CargoFeatures,
95-
/// rustc target
96-
pub target: Option<String>,
95+
/// rustc targets
96+
pub targets: Vec<String>,
9797
/// Don't load sysroot crates (`std`, `core` & friends). Might be useful
9898
/// when debugging isolated issues.
9999
pub no_sysroot: bool,
@@ -269,11 +269,7 @@ impl CargoWorkspace {
269269
config: &CargoConfig,
270270
progress: &dyn Fn(String),
271271
) -> Result<cargo_metadata::Metadata> {
272-
let target = config
273-
.target
274-
.clone()
275-
.or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env))
276-
.or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env));
272+
let targets = find_list_of_build_targets(config, cargo_toml);
277273

278274
let mut meta = MetadataCommand::new();
279275
meta.cargo_path(toolchain::cargo());
@@ -295,8 +291,12 @@ impl CargoWorkspace {
295291
}
296292
meta.current_dir(current_dir.as_os_str());
297293

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

302302
// FIXME: Fetching metadata is a slow process, as it might require
@@ -466,10 +466,23 @@ impl CargoWorkspace {
466466
}
467467
}
468468

469+
fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec<String> {
470+
if !config.targets.is_empty() {
471+
return config.targets.clone();
472+
}
473+
474+
let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env);
475+
if !build_targets.is_empty() {
476+
return build_targets;
477+
}
478+
479+
rustc_discover_host_triple(cargo_toml, &config.extra_env)
480+
}
481+
469482
fn rustc_discover_host_triple(
470483
cargo_toml: &ManifestPath,
471484
extra_env: &FxHashMap<String, String>,
472-
) -> Option<String> {
485+
) -> Vec<String> {
473486
let mut rustc = Command::new(toolchain::rustc());
474487
rustc.envs(extra_env);
475488
rustc.current_dir(cargo_toml.parent()).arg("-vV");
@@ -479,37 +492,46 @@ fn rustc_discover_host_triple(
479492
let field = "host: ";
480493
let target = stdout.lines().find_map(|l| l.strip_prefix(field));
481494
if let Some(target) = target {
482-
Some(target.to_string())
495+
[target.to_string()].to_vec()
483496
} else {
484497
// If we fail to resolve the host platform, it's not the end of the world.
485498
tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout);
486-
None
499+
Vec::new()
487500
}
488501
}
489502
Err(e) => {
490503
tracing::warn!("Failed to discover host platform: {}", e);
491-
None
504+
Vec::new()
492505
}
493506
}
494507
}
495508

496509
fn cargo_config_build_target(
497510
cargo_toml: &ManifestPath,
498511
extra_env: &FxHashMap<String, String>,
499-
) -> Option<String> {
512+
) -> Vec<String> {
500513
let mut cargo_config = Command::new(toolchain::cargo());
501514
cargo_config.envs(extra_env);
502515
cargo_config
503516
.current_dir(cargo_toml.parent())
504517
.args(&["-Z", "unstable-options", "config", "get", "build.target"])
505518
.env("RUSTC_BOOTSTRAP", "1");
506519
// if successful we receive `build.target = "target-triple"`
520+
// or `build.target = ["<target 1>", ..]`
507521
tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
508-
match utf8_stdout(cargo_config) {
509-
Ok(stdout) => stdout
510-
.strip_prefix("build.target = \"")
511-
.and_then(|stdout| stdout.strip_suffix('"'))
512-
.map(ToOwned::to_owned),
513-
Err(_) => None,
522+
utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default()
523+
}
524+
525+
fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> {
526+
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
527+
528+
if !trimmed.starts_with('[') {
529+
return [trimmed.to_string()].to_vec();
530+
}
531+
532+
let res = serde_json::from_str(trimmed);
533+
if let Err(e) = &res {
534+
tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e);
514535
}
536+
res.unwrap_or_default()
515537
}

crates/project-model/src/project_json.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub struct Crate {
3535
pub(crate) version: Option<String>,
3636
pub(crate) deps: Vec<Dependency>,
3737
pub(crate) cfg: Vec<CfgFlag>,
38+
// XXX: support multiple targets ? (Rust 1.64.0+)
3839
pub(crate) target: Option<String>,
3940
pub(crate) env: FxHashMap<String, String>,
4041
pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,

crates/project-model/src/rustc_cfg.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath};
99

1010
pub(crate) fn get(
1111
cargo_toml: Option<&ManifestPath>,
12-
target: Option<&str>,
12+
targets: &[String],
1313
extra_env: &FxHashMap<String, String>,
1414
) -> Vec<CfgFlag> {
1515
let _p = profile::span("rustc_cfg::get");
@@ -23,7 +23,7 @@ pub(crate) fn get(
2323
}
2424
}
2525

26-
match get_rust_cfgs(cargo_toml, target, extra_env) {
26+
match get_rust_cfgs(cargo_toml, targets, extra_env) {
2727
Ok(rustc_cfgs) => {
2828
tracing::debug!(
2929
"rustc cfgs found: {:?}",
@@ -42,7 +42,7 @@ pub(crate) fn get(
4242

4343
fn get_rust_cfgs(
4444
cargo_toml: Option<&ManifestPath>,
45-
target: Option<&str>,
45+
targets: &[String],
4646
extra_env: &FxHashMap<String, String>,
4747
) -> Result<String> {
4848
if let Some(cargo_toml) = cargo_toml {
@@ -52,7 +52,7 @@ fn get_rust_cfgs(
5252
.current_dir(cargo_toml.parent())
5353
.args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
5454
.env("RUSTC_BOOTSTRAP", "1");
55-
if let Some(target) = target {
55+
for target in targets {
5656
cargo_config.args(&["--target", target]);
5757
}
5858
match utf8_stdout(cargo_config) {
@@ -64,7 +64,7 @@ fn get_rust_cfgs(
6464
let mut cmd = Command::new(toolchain::rustc());
6565
cmd.envs(extra_env);
6666
cmd.args(&["--print", "cfg", "-O"]);
67-
if let Some(target) = target {
67+
for target in targets {
6868
cmd.args(&["--target", target]);
6969
}
7070
utf8_stdout(cmd)

crates/project-model/src/workspace.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,7 @@ impl ProjectWorkspace {
156156
})?;
157157
let project_location = project_json.parent().to_path_buf();
158158
let project_json = ProjectJson::new(&project_location, data);
159-
ProjectWorkspace::load_inline(
160-
project_json,
161-
config.target.as_deref(),
162-
&config.extra_env,
163-
)?
159+
ProjectWorkspace::load_inline(project_json, &config.targets, &config.extra_env)?
164160
}
165161
ProjectManifest::CargoToml(cargo_toml) => {
166162
let cargo_version = utf8_stdout({
@@ -226,7 +222,7 @@ impl ProjectWorkspace {
226222
};
227223

228224
let rustc_cfg =
229-
rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
225+
rustc_cfg::get(Some(&cargo_toml), &config.targets, &config.extra_env);
230226

231227
let cfg_overrides = config.cfg_overrides();
232228
ProjectWorkspace::Cargo {
@@ -246,7 +242,7 @@ impl ProjectWorkspace {
246242

247243
pub fn load_inline(
248244
project_json: ProjectJson,
249-
target: Option<&str>,
245+
targets: &[String],
250246
extra_env: &FxHashMap<String, String>,
251247
) -> Result<ProjectWorkspace> {
252248
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
@@ -269,7 +265,7 @@ impl ProjectWorkspace {
269265
(None, None) => None,
270266
};
271267

272-
let rustc_cfg = rustc_cfg::get(None, target, extra_env);
268+
let rustc_cfg = rustc_cfg::get(None, targets, extra_env);
273269
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
274270
}
275271

@@ -281,7 +277,7 @@ impl ProjectWorkspace {
281277
.ok_or_else(|| format_err!("No detached files to load"))?,
282278
&Default::default(),
283279
)?;
284-
let rustc_cfg = rustc_cfg::get(None, None, &Default::default());
280+
let rustc_cfg = rustc_cfg::get(None, &[], &Default::default());
285281
Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
286282
}
287283

@@ -499,7 +495,7 @@ fn project_json_to_crate_graph(
499495
let target_cfgs = match krate.target.as_deref() {
500496
Some(target) => cfg_cache
501497
.entry(target)
502-
.or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)),
498+
.or_insert_with(|| rustc_cfg::get(None, &[target.into()], extra_env)),
503499
None => &rustc_cfg,
504500
};
505501

crates/rust-analyzer/src/config.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,10 @@ config_data! {
9696
cargo_noDefaultFeatures: bool = "false",
9797
/// Internal config for debugging, disables loading of sysroot crates.
9898
cargo_noSysroot: bool = "false",
99-
/// Compilation target override (target triple).
100-
cargo_target: Option<String> = "null",
99+
/// Compilation targets override (target triples).
100+
/// Setting this with multiple elements is like passing multiple
101+
/// `--target` flags to `cargo`, only available on Rust 1.64.0+.
102+
cargo_target: Vec<String> = "[]",
101103
/// Unsets `#[cfg(test)]` for the specified crates.
102104
cargo_unsetTest: Vec<String> = "[\"core\"]",
103105

@@ -139,9 +141,9 @@ config_data! {
139141
/// ```
140142
/// .
141143
checkOnSave_overrideCommand: Option<Vec<String>> = "null",
142-
/// Check for a specific target. Defaults to
143-
/// `#rust-analyzer.cargo.target#`.
144-
checkOnSave_target: Option<String> = "null",
144+
/// Check for specific targets. Defaults to
145+
/// `#rust-analyzer.cargo.targets#`.
146+
checkOnSave_target: Vec<String> = "[]",
145147

146148
/// Toggles the additional completions that automatically add imports when completed.
147149
/// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
@@ -1037,7 +1039,7 @@ impl Config {
10371039
no_default_features: self.data.cargo_noDefaultFeatures,
10381040
},
10391041
},
1040-
target: self.data.cargo_target.clone(),
1042+
targets: self.data.cargo_target.clone(),
10411043
no_sysroot: self.data.cargo_noSysroot,
10421044
rustc_source,
10431045
unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
@@ -1077,11 +1079,15 @@ impl Config {
10771079
}
10781080
Some(_) | None => FlycheckConfig::CargoCommand {
10791081
command: self.data.checkOnSave_command.clone(),
1080-
target_triple: self
1082+
target_triples: self
10811083
.data
10821084
.checkOnSave_target
1083-
.clone()
1084-
.or_else(|| self.data.cargo_target.clone()),
1085+
.is_empty()
1086+
// If empty, fallback to `cargo_target`
1087+
.then_some(&self.data.cargo_target)
1088+
// Else use specified data
1089+
.unwrap_or(&self.data.checkOnSave_target)
1090+
.clone(),
10851091
all_targets: self.data.checkOnSave_allTargets,
10861092
no_default_features: self
10871093
.data

crates/rust-analyzer/src/reload.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ impl GlobalState {
142142
LinkedProject::InlineJsonProject(it) => {
143143
project_model::ProjectWorkspace::load_inline(
144144
it.clone(),
145-
cargo_config.target.as_deref(),
145+
&cargo_config.targets,
146146
&cargo_config.extra_env,
147147
)
148148
}

docs/user/generated_config.adoc

+7-5
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,12 @@ Whether to pass `--no-default-features` to cargo.
6969
--
7070
Internal config for debugging, disables loading of sysroot crates.
7171
--
72-
[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`)::
72+
[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `[]`)::
7373
+
7474
--
75-
Compilation target override (target triple).
75+
Compilation targets override (target triples).
76+
Setting this with multiple elements is like passing multiple
77+
`--target` flags to `cargo`, only available on Rust 1.64.0+.
7678
--
7779
[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`)::
7880
+
@@ -141,11 +143,11 @@ cargo check --workspace --message-format=json --all-targets
141143
```
142144
.
143145
--
144-
[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`)::
146+
[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `[]`)::
145147
+
146148
--
147-
Check for a specific target. Defaults to
148-
`#rust-analyzer.cargo.target#`.
149+
Check for specific targets. Defaults to
150+
`#rust-analyzer.cargo.targets#`.
149151
--
150152
[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
151153
+

0 commit comments

Comments
 (0)