about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2021-05-08 18:17:18 +0200
committerLukas Wirth <lukastw97@gmail.com>2021-05-08 18:17:18 +0200
commit8989fb8315538aece975663c3be4aba867e9ee86 (patch)
treed44aa077a01ccae27a94b01c58e7ecec3e3d2709
parent526040eea8886a748dfd0a5449526f37a8bcf6af (diff)
downloadrust-8989fb8315538aece975663c3be4aba867e9ee86.tar.gz
rust-8989fb8315538aece975663c3be4aba867e9ee86.zip
Discover rustc_cfg through unstable cargo options
-rw-r--r--crates/project_model/src/cargo_workspace.rs71
-rw-r--r--crates/project_model/src/rustc_cfg.rs38
-rw-r--r--crates/project_model/src/workspace.rs7
3 files changed, 83 insertions, 33 deletions
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index bc6e203414e..f1ad00d36dd 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -201,31 +201,12 @@ impl CargoWorkspace {
         if let Some(parent) = cargo_toml.parent() {
             meta.current_dir(parent.to_path_buf());
         }
-        let target = if let Some(target) = config.target.as_ref() {
+        let target = if let Some(target) = &config.target {
             Some(target.clone())
+        } else if let stdout @ Some(_) = cargo_config_build_target(cargo_toml) {
+            stdout
         } else {
-            // cargo metadata defaults to giving information for _all_ targets.
-            // In the absence of a preference from the user, we use the host platform.
-            let mut rustc = Command::new(toolchain::rustc());
-            rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
-            log::debug!("Discovering host platform by {:?}", rustc);
-            match utf8_stdout(rustc) {
-                Ok(stdout) => {
-                    let field = "host: ";
-                    let target = stdout.lines().find_map(|l| l.strip_prefix(field));
-                    if let Some(target) = target {
-                        Some(target.to_string())
-                    } else {
-                        // If we fail to resolve the host platform, it's not the end of the world.
-                        log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
-                        None
-                    }
-                }
-                Err(e) => {
-                    log::warn!("Failed to discover host platform: {}", e);
-                    None
-                }
-            }
+            rustc_discover_host_triple(cargo_toml)
         };
         if let Some(target) = target {
             meta.other_options(vec![String::from("--filter-platform"), target]);
@@ -368,3 +349,47 @@ impl CargoWorkspace {
         self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
     }
 }
+
+fn rustc_discover_host_triple(cargo_toml: &AbsPath) -> Option<String> {
+    let mut rustc = Command::new(toolchain::rustc());
+    rustc.current_dir(cargo_toml.parent().unwrap()).arg("-vV");
+    log::debug!("Discovering host platform by {:?}", rustc);
+    match utf8_stdout(rustc) {
+        Ok(stdout) => {
+            let field = "host: ";
+            let target = stdout.lines().find_map(|l| l.strip_prefix(field));
+            if let Some(target) = target {
+                Some(target.to_string())
+            } else {
+                // If we fail to resolve the host platform, it's not the end of the world.
+                log::info!("rustc -vV did not report host platform, got:\n{}", stdout);
+                None
+            }
+        }
+        Err(e) => {
+            log::warn!("Failed to discover host platform: {}", e);
+            None
+        }
+    }
+}
+
+fn cargo_config_build_target(cargo_toml: &AbsPath) -> Option<String> {
+    let mut cargo_config = Command::new(toolchain::cargo());
+    cargo_config.current_dir(cargo_toml.parent().unwrap()).args(&[
+        "+nightly",
+        "-Z",
+        "unstable-options",
+        "config",
+        "get",
+        "build.target",
+    ]);
+    // if successful we receive `build.target = "target-triple"`
+    log::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,
+    }
+}
diff --git a/crates/project_model/src/rustc_cfg.rs b/crates/project_model/src/rustc_cfg.rs
index 312708575e0..6de40cfe2ae 100644
--- a/crates/project_model/src/rustc_cfg.rs
+++ b/crates/project_model/src/rustc_cfg.rs
@@ -2,9 +2,11 @@
 
 use std::process::Command;
 
+use paths::AbsPath;
+
 use crate::{cfg_flag::CfgFlag, utf8_stdout};
 
-pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
+pub(crate) fn get(cargo_toml: Option<&AbsPath>, target: Option<&str>) -> Vec<CfgFlag> {
     let _p = profile::span("rustc_cfg::get");
     let mut res = Vec::with_capacity(6 * 2 + 1);
 
@@ -17,12 +19,34 @@ pub(crate) fn get(target: Option<&str>) -> Vec<CfgFlag> {
     }
 
     let rustc_cfgs = {
-        let mut cmd = Command::new(toolchain::rustc());
-        cmd.args(&["--print", "cfg", "-O"]);
-        if let Some(target) = target {
-            cmd.args(&["--target", target]);
-        }
-        utf8_stdout(cmd)
+        cargo_toml
+            .and_then(|cargo_toml| {
+                let mut cargo_config = Command::new(toolchain::cargo());
+                cargo_config.current_dir(cargo_toml.parent().unwrap()).args(&[
+                    "+nightly",
+                    "-Z",
+                    "unstable-options",
+                    "rustc",
+                    "--print",
+                    "cfg",
+                ]);
+                if let Some(target) = target {
+                    cargo_config.args(&["--target", target]);
+                }
+                utf8_stdout(cargo_config).ok()
+            })
+            .map_or_else(
+                || {
+                    // using unstable cargo features failed, fall back to using plain rustc
+                    let mut cmd = Command::new(toolchain::rustc());
+                    cmd.args(&["--print", "cfg", "-O"]);
+                    if let Some(target) = target {
+                        cmd.args(&["--target", target]);
+                    }
+                    utf8_stdout(cmd)
+                },
+                Ok,
+            )
     };
 
     match rustc_cfgs {
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 2fcd0f8face..84c702fdf7e 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -143,7 +143,8 @@ impl ProjectWorkspace {
                 } else {
                     None
                 };
-                let rustc_cfg = rustc_cfg::get(config.target.as_deref());
+
+                let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
                 ProjectWorkspace::Cargo { cargo, sysroot, rustc, rustc_cfg }
             }
         };
@@ -159,7 +160,7 @@ impl ProjectWorkspace {
             Some(path) => Some(Sysroot::load(path)?),
             None => None,
         };
-        let rustc_cfg = rustc_cfg::get(target);
+        let rustc_cfg = rustc_cfg::get(None, target);
         Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
     }
 
@@ -310,7 +311,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(Some(target)))
+                    cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target)))
                 }
                 None => &rustc_cfg,
             };