From: Mark Simulacrum Date: Mon, 21 Aug 2017 11:46:31 +0000 (-0600) Subject: Discover crate type information late if necessary. X-Git-Tag: archive/raspbian/0.35.0-2+rpi1~3^2^2^2^2^2^2^2~22^2~7^2~3^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4cfaf9a591e5c055b87b8eb265c665a4cc1305d9;p=cargo.git Discover crate type information late if necessary. Some crates aren't found during eager crate-type searching due to being behind `cfg(...)` flags. We still want to be able to handle these, though, so when necessary we now call rustc again to get crate-type information for these cfg-ed crates. --- diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index 5b67830e7..865f8b42a 100755 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -1,19 +1,21 @@ #![allow(deprecated)] use std::collections::{HashSet, HashMap, BTreeSet}; +use std::collections::hash_map::Entry; use std::env; use std::fmt; use std::hash::{Hasher, Hash, SipHasher}; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use std::sync::Arc; +use std::cell::RefCell; use jobserver::Client; use core::{Package, PackageId, PackageSet, Resolve, Target, Profile}; use core::{TargetKind, Profiles, Dependency, Workspace}; use core::dependency::Kind as DepKind; -use util::{self, internal, Config, profile, Cfg, CfgExpr}; +use util::{self, ProcessBuilder, internal, Config, profile, Cfg, CfgExpr}; use util::errors::{CargoResult, CargoResultExt}; use super::TargetConfig; @@ -58,10 +60,28 @@ pub struct Context<'a, 'cfg: 'a> { #[derive(Clone, Default)] struct TargetInfo { - crate_types: HashMap>, + crate_type_process: Option, + crate_types: RefCell>>, cfg: Option>, } +impl TargetInfo { + fn discover_crate_type(&self, crate_type: &str) -> CargoResult> { + let mut process = self.crate_type_process.clone().unwrap(); + + process.arg("--crate-type").arg(crate_type); + + let output = process.exec_with_output().chain_err(|| { + format!("failed to run `rustc` to learn about \ + crate-type {} information", crate_type) + })?; + + let error = str::from_utf8(&output.stderr).unwrap(); + let output = str::from_utf8(&output.stdout).unwrap(); + Ok(parse_crate_type(crate_type, error, &mut output.lines())?) + } +} + #[derive(Clone)] pub struct Metadata(u64); @@ -220,13 +240,16 @@ impl<'a, 'cfg> Context<'a, 'cfg> { .args(&rustflags) .env_remove("RUST_LOG"); - for crate_type in crate_types { - process.arg("--crate-type").arg(crate_type); - } if kind == Kind::Target { process.arg("--target").arg(&self.target_triple()); } + let crate_type_process = process.clone(); + + for crate_type in crate_types { + process.arg("--crate-type").arg(crate_type); + } + let mut with_cfg = process.clone(); with_cfg.arg("--print=sysroot"); with_cfg.arg("--print=cfg"); @@ -245,29 +268,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> { let mut lines = output.lines(); let mut map = HashMap::new(); for crate_type in crate_types { - let not_supported = error.lines().any(|line| { - (line.contains("unsupported crate type") || - line.contains("unknown crate type")) && - line.contains(crate_type) - }); - if not_supported { - map.insert(crate_type.to_string(), None); - continue; - } - let line = match lines.next() { - Some(line) => line, - None => bail!("malformed output when learning about \ - target-specific information from rustc"), - }; - let mut parts = line.trim().split("___"); - let prefix = parts.next().unwrap(); - let suffix = match parts.next() { - Some(part) => part, - None => bail!("output of --print=file-names has changed in \ - the compiler, cannot parse"), - }; - - map.insert(crate_type.to_string(), Some((prefix.to_string(), suffix.to_string()))); + let out = parse_crate_type(crate_type, error, &mut lines)?; + map.insert(crate_type.to_string(), out); } if has_cfg_and_sysroot { @@ -303,7 +305,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> { Kind::Target => &mut self.target_info, Kind::Host => &mut self.host_info, }; - info.crate_types = map; + info.crate_type_process = Some(crate_type_process); + info.crate_types = RefCell::new(map); info.cfg = cfg; Ok(()) } @@ -596,8 +599,17 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } else { let mut add = |crate_type: &str, linkable: bool| -> CargoResult<()> { let crate_type = if crate_type == "lib" {"rlib"} else {crate_type}; - match info.crate_types.get(crate_type) { - Some(&Some((ref prefix, ref suffix))) => { + let mut crate_types = info.crate_types.borrow_mut(); + let entry = crate_types.entry(crate_type.to_string()); + let crate_type_info = match entry { + Entry::Occupied(o) => &*o.into_mut(), + Entry::Vacant(v) => { + let value = info.discover_crate_type(&v.key())?; + &*v.insert(value) + } + }; + match *crate_type_info { + Some((ref prefix, ref suffix)) => { let filename = out_dir.join(format!("{}{}{}", prefix, stem, suffix)); let link_dst = link_stem.clone().map(|(ld, ls)| { ld.join(format!("{}{}{}", prefix, ls, suffix)) @@ -606,14 +618,10 @@ impl<'a, 'cfg> Context<'a, 'cfg> { Ok(()) } // not supported, don't worry about it - Some(&None) => { + None => { unsupported.push(crate_type.to_string()); Ok(()) } - None => { - bail!("failed to learn about crate-type `{}` early on", - crate_type) - } } }; @@ -1095,3 +1103,32 @@ impl fmt::Display for Metadata { write!(f, "{:016x}", self.0) } } + +fn parse_crate_type( + crate_type: &str, + error: &str, + lines: &mut str::Lines, +) -> CargoResult> { + let not_supported = error.lines().any(|line| { + (line.contains("unsupported crate type") || + line.contains("unknown crate type")) && + line.contains(crate_type) + }); + if not_supported { + return Ok(None); + } + let line = match lines.next() { + Some(line) => line, + None => bail!("malformed output when learning about \ + crate-type {} information", crate_type), + }; + let mut parts = line.trim().split("___"); + let prefix = parts.next().unwrap(); + let suffix = match parts.next() { + Some(part) => part, + None => bail!("output of --print=file-names has changed in \ + the compiler, cannot parse"), + }; + + Ok(Some((prefix.to_string(), suffix.to_string()))) +} diff --git a/tests/proc-macro.rs b/tests/proc-macro.rs index ee04a74e1..3e168c49b 100644 --- a/tests/proc-macro.rs +++ b/tests/proc-macro.rs @@ -5,6 +5,60 @@ use cargotest::is_nightly; use cargotest::support::{project, execs}; use hamcrest::assert_that; +#[test] +fn probe_cfg_before_crate_type_discovery() { + if !is_nightly() { + return; + } + + let client = project("client") + .file("Cargo.toml", r#" + [package] + name = "client" + version = "0.0.1" + authors = [] + + [target.'cfg(not(stage300))'.dependencies.noop] + path = "../noop" + "#) + .file("src/main.rs", r#" + #![feature(proc_macro)] + + #[macro_use] + extern crate noop; + + #[derive(Noop)] + struct X; + + fn main() {} + "#); + let noop = project("noop") + .file("Cargo.toml", r#" + [package] + name = "noop" + version = "0.0.1" + authors = [] + + [lib] + proc-macro = true + "#) + .file("src/lib.rs", r#" + #![feature(proc_macro, proc_macro_lib)] + + extern crate proc_macro; + use proc_macro::TokenStream; + + #[proc_macro_derive(Noop)] + pub fn noop(_input: TokenStream) -> TokenStream { + "".parse().unwrap() + } + "#); + noop.build(); + + assert_that(client.cargo_process("build"), + execs().with_status(0)); +} + #[test] fn noop() { if !is_nightly() {