Skip to content

Commit

Permalink
feat: Support passing multiple targets to cargo (for Rust 1.64.0+)
Browse files Browse the repository at this point in the history
  • Loading branch information
poliorcetics committed Sep 25, 2022
1 parent 499c6f6 commit 65e8b97
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 64 deletions.
6 changes: 3 additions & 3 deletions crates/flycheck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub use cargo_metadata::diagnostic::{
pub enum FlycheckConfig {
CargoCommand {
command: String,
target_triple: Option<String>,
target_triples: Vec<String>,
all_targets: bool,
no_default_features: bool,
all_features: bool,
Expand Down Expand Up @@ -253,7 +253,7 @@ impl FlycheckActor {
let mut cmd = match &self.config {
FlycheckConfig::CargoCommand {
command,
target_triple,
target_triples,
no_default_features,
all_targets,
all_features,
Expand All @@ -267,7 +267,7 @@ impl FlycheckActor {
cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
.arg(self.workspace_root.join("Cargo.toml").as_os_str());

if let Some(target) = target_triple {
for target in target_triples {
cmd.args(&["--target", target.as_str()]);
}
if *all_targets {
Expand Down
6 changes: 3 additions & 3 deletions crates/project-model/src/build_scripts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ impl WorkspaceBuildScripts {
cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);

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

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

match &config.features {
Expand Down
54 changes: 38 additions & 16 deletions crates/project-model/src/cargo_workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ impl Default for CargoFeatures {
pub struct CargoConfig {
/// List of features to activate.
pub features: CargoFeatures,
/// rustc target
pub target: Option<String>,
/// rustc targets
pub targets: Vec<String>,
/// Don't load sysroot crates (`std`, `core` & friends). Might be useful
/// when debugging isolated issues.
pub no_sysroot: bool,
Expand Down Expand Up @@ -269,11 +269,7 @@ impl CargoWorkspace {
config: &CargoConfig,
progress: &dyn Fn(String),
) -> Result<cargo_metadata::Metadata> {
let target = config
.target
.clone()
.or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env))
.or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env));
let targets = find_list_of_build_targets(config, cargo_toml);

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

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

// FIXME: Fetching metadata is a slow process, as it might require
Expand Down Expand Up @@ -466,6 +466,19 @@ impl CargoWorkspace {
}
}

fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec<String> {
if !config.targets.is_empty() {
return config.targets.clone();
}

let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env);
if !build_targets.is_empty() {
return build_targets;
}

rustc_discover_host_triple(cargo_toml, &config.extra_env).into_iter().collect()
}

fn rustc_discover_host_triple(
cargo_toml: &ManifestPath,
extra_env: &FxHashMap<String, String>,
Expand Down Expand Up @@ -496,20 +509,29 @@ fn rustc_discover_host_triple(
fn cargo_config_build_target(
cargo_toml: &ManifestPath,
extra_env: &FxHashMap<String, String>,
) -> Option<String> {
) -> Vec<String> {
let mut cargo_config = Command::new(toolchain::cargo());
cargo_config.envs(extra_env);
cargo_config
.current_dir(cargo_toml.parent())
.args(&["-Z", "unstable-options", "config", "get", "build.target"])
.env("RUSTC_BOOTSTRAP", "1");
// if successful we receive `build.target = "target-triple"`
// or `build.target = ["<target 1>", ..]`
tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
match utf8_stdout(cargo_config) {
Ok(stdout) => stdout
.strip_prefix("build.target = \"")
.and_then(|stdout| stdout.strip_suffix('"'))
.map(ToOwned::to_owned),
Err(_) => None,
utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default()
}

fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> {
let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');

if !trimmed.starts_with('[') {
return [trimmed.to_string()].to_vec();
}

let res = serde_json::from_str(trimmed);
if let Err(e) = &res {
tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e);
}
res.unwrap_or_default()
}
1 change: 1 addition & 0 deletions crates/project-model/src/project_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct Crate {
pub(crate) version: Option<String>,
pub(crate) deps: Vec<Dependency>,
pub(crate) cfg: Vec<CfgFlag>,
// XXX: support multiple targets ? (Rust 1.64.0+)
pub(crate) target: Option<String>,
pub(crate) env: FxHashMap<String, String>,
pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
Expand Down
10 changes: 5 additions & 5 deletions crates/project-model/src/rustc_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath};

pub(crate) fn get(
cargo_toml: Option<&ManifestPath>,
target: Option<&str>,
targets: &[String],
extra_env: &FxHashMap<String, String>,
) -> Vec<CfgFlag> {
let _p = profile::span("rustc_cfg::get");
Expand All @@ -23,7 +23,7 @@ pub(crate) fn get(
}
}

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

fn get_rust_cfgs(
cargo_toml: Option<&ManifestPath>,
target: Option<&str>,
targets: &[String],
extra_env: &FxHashMap<String, String>,
) -> Result<String> {
if let Some(cargo_toml) = cargo_toml {
Expand All @@ -52,7 +52,7 @@ fn get_rust_cfgs(
.current_dir(cargo_toml.parent())
.args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
.env("RUSTC_BOOTSTRAP", "1");
if let Some(target) = target {
for target in targets {
cargo_config.args(&["--target", target]);
}
match utf8_stdout(cargo_config) {
Expand All @@ -64,7 +64,7 @@ fn get_rust_cfgs(
let mut cmd = Command::new(toolchain::rustc());
cmd.envs(extra_env);
cmd.args(&["--print", "cfg", "-O"]);
if let Some(target) = target {
for target in targets {
cmd.args(&["--target", target]);
}
utf8_stdout(cmd)
Expand Down
16 changes: 6 additions & 10 deletions crates/project-model/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,7 @@ impl ProjectWorkspace {
})?;
let project_location = project_json.parent().to_path_buf();
let project_json = ProjectJson::new(&project_location, data);
ProjectWorkspace::load_inline(
project_json,
config.target.as_deref(),
&config.extra_env,
)?
ProjectWorkspace::load_inline(project_json, &config.targets, &config.extra_env)?
}
ProjectManifest::CargoToml(cargo_toml) => {
let cargo_version = utf8_stdout({
Expand Down Expand Up @@ -226,7 +222,7 @@ impl ProjectWorkspace {
};

let rustc_cfg =
rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), &config.extra_env);
rustc_cfg::get(Some(&cargo_toml), &config.targets, &config.extra_env);

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

pub fn load_inline(
project_json: ProjectJson,
target: Option<&str>,
targets: &[String],
extra_env: &FxHashMap<String, String>,
) -> Result<ProjectWorkspace> {
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
Expand All @@ -269,7 +265,7 @@ impl ProjectWorkspace {
(None, None) => None,
};

let rustc_cfg = rustc_cfg::get(None, target, extra_env);
let rustc_cfg = rustc_cfg::get(None, targets, extra_env);
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
}

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

Expand Down Expand Up @@ -499,7 +495,7 @@ fn project_json_to_crate_graph(
let target_cfgs = match krate.target.as_deref() {
Some(target) => cfg_cache
.entry(target)
.or_insert_with(|| rustc_cfg::get(None, Some(target), extra_env)),
.or_insert_with(|| rustc_cfg::get(None, &[target.into()], extra_env)),
None => &rustc_cfg,
};

Expand Down
24 changes: 15 additions & 9 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ config_data! {
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",
/// Compilation targets override (target triples).
/// Setting this with multiple elements is like passing multiple
/// `--target` flags to `cargo`, only available on Rust 1.64.0+.
cargo_target: Vec<String> = "[]",
/// Unsets `#[cfg(test)]` for the specified crates.
cargo_unsetTest: Vec<String> = "[\"core\"]",

Expand Down Expand Up @@ -139,9 +141,9 @@ config_data! {
/// ```
/// .
checkOnSave_overrideCommand: Option<Vec<String>> = "null",
/// Check for a specific target. Defaults to
/// `#rust-analyzer.cargo.target#`.
checkOnSave_target: Option<String> = "null",
/// Check for specific targets. Defaults to
/// `#rust-analyzer.cargo.targets#`.
checkOnSave_target: Vec<String> = "[]",

/// Toggles the additional completions that automatically add imports when completed.
/// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
Expand Down Expand Up @@ -1037,7 +1039,7 @@ impl Config {
no_default_features: self.data.cargo_noDefaultFeatures,
},
},
target: self.data.cargo_target.clone(),
targets: self.data.cargo_target.clone(),
no_sysroot: self.data.cargo_noSysroot,
rustc_source,
unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
Expand Down Expand Up @@ -1077,11 +1079,15 @@ impl Config {
}
Some(_) | None => FlycheckConfig::CargoCommand {
command: self.data.checkOnSave_command.clone(),
target_triple: self
target_triples: self
.data
.checkOnSave_target
.clone()
.or_else(|| self.data.cargo_target.clone()),
.is_empty()
// If empty, fallback to `cargo_target`
.then_some(&self.data.cargo_target)
// Else use specified data
.unwrap_or(&self.data.checkOnSave_target)
.clone(),
all_targets: self.data.checkOnSave_allTargets,
no_default_features: self
.data
Expand Down
2 changes: 1 addition & 1 deletion crates/rust-analyzer/src/reload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl GlobalState {
LinkedProject::InlineJsonProject(it) => {
project_model::ProjectWorkspace::load_inline(
it.clone(),
cargo_config.target.as_deref(),
&cargo_config.targets,
&cargo_config.extra_env,
)
}
Expand Down
12 changes: 7 additions & 5 deletions docs/user/generated_config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@ Whether to pass `--no-default-features` to cargo.
--
Internal config for debugging, disables loading of sysroot crates.
--
[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`)::
[[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `[]`)::
+
--
Compilation target override (target triple).
Compilation targets override (target triples).
Setting this with multiple elements is like passing multiple
`--target` flags to `cargo`, only available on Rust 1.64.0+.
--
[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`)::
+
Expand Down Expand Up @@ -141,11 +143,11 @@ cargo check --workspace --message-format=json --all-targets
```
.
--
[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`)::
[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `[]`)::
+
--
Check for a specific target. Defaults to
`#rust-analyzer.cargo.target#`.
Check for specific targets. Defaults to
`#rust-analyzer.cargo.targets#`.
--
[[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
+
Expand Down
24 changes: 12 additions & 12 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -474,12 +474,12 @@
"type": "boolean"
},
"rust-analyzer.cargo.target": {
"markdownDescription": "Compilation target override (target triple).",
"default": null,
"type": [
"null",
"string"
]
"markdownDescription": "Compilation targets override (target triples).\nSetting this with multiple elements is like passing multiple\n`--target` flags to `cargo`, only available on Rust 1.64.0+.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.cargo.unsetTest": {
"markdownDescription": "Unsets `#[cfg(test)]` for the specified crates.",
Expand Down Expand Up @@ -563,12 +563,12 @@
}
},
"rust-analyzer.checkOnSave.target": {
"markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.",
"default": null,
"type": [
"null",
"string"
]
"markdownDescription": "Check for specific targets. Defaults to\n`#rust-analyzer.cargo.targets#`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"rust-analyzer.completion.autoimport.enable": {
"markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
Expand Down

0 comments on commit 65e8b97

Please sign in to comment.