From c5a6f06ff3e7aceb0da6cc432ea48e26e44ac568 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 26 Jul 2019 12:53:25 -0700 Subject: [PATCH] Clean up TargetInfo --- src/cargo/core/compiler/build_context/mod.rs | 2 +- .../compiler/build_context/target_info.rs | 132 +++++++++++------- src/cargo/core/compiler/compilation.rs | 44 +++--- src/cargo/core/dependency.rs | 7 +- src/cargo/util/rustc.rs | 40 +----- tests/testsuite/rustc_info_cache.rs | 14 +- 6 files changed, 122 insertions(+), 117 deletions(-) diff --git a/src/cargo/core/compiler/build_context/mod.rs b/src/cargo/core/compiler/build_context/mod.rs index 324c052ad24..18956632152 100644 --- a/src/cargo/core/compiler/build_context/mod.rs +++ b/src/cargo/core/compiler/build_context/mod.rs @@ -127,7 +127,7 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> { Kind::Host => &self.host_info, Kind::Target => &self.target_info, }; - info.cfg().unwrap_or(&[]) + info.cfg() } /// Gets the host architecture triple. diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index 8abc579e713..ecdb4239c65 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -9,17 +9,34 @@ use crate::core::TargetKind; use crate::util::CfgExpr; use crate::util::{CargoResult, CargoResultExt, Cfg, Config, ProcessBuilder, Rustc}; +/// Information about the platform target gleaned from querying rustc. +/// +/// The `BuildContext` keeps two of these, one for the host and one for the +/// target. If no target is specified, it uses a clone from the host. #[derive(Clone)] pub struct TargetInfo { - crate_type_process: Option, + /// A base process builder for discovering crate type information. In + /// particular, this is used to determine the output filename prefix and + /// suffix for a crate type. + crate_type_process: ProcessBuilder, + /// Cache of output filename prefixes and suffixes. + /// + /// The key is the crate type name (like `cdylib`) and the value is + /// `Some((prefix, suffix))`, for example `libcargo.so` would be + /// `Some(("lib", ".so")). The value is `None` if the crate type is not + /// supported. crate_types: RefCell>>, - cfg: Option>, - pub sysroot_libdir: Option, + /// `cfg` information extracted from `rustc --print=cfg`. + cfg: Vec, + /// Path to the "lib" directory in the sysroot. + pub sysroot_libdir: PathBuf, + /// Extra flags to pass to `rustc`, see `env_args`. pub rustflags: Vec, + /// Extra flags to pass to `rustdoc`, see `env_args`. pub rustdocflags: Vec, } -/// Type of each file generated by a Unit. +/// Kind of each file generated by a Unit, part of `FileType`. #[derive(Clone, PartialEq, Eq, Debug)] pub enum FileFlavor { /// Not a special file type. @@ -30,9 +47,13 @@ pub enum FileFlavor { DebugInfo, } +/// Type of each file generated by a Unit. pub struct FileType { + /// The kind of file. pub flavor: FileFlavor, + /// The suffix for the file (for example, `.rlib`). suffix: String, + /// The prefix for the file (for example, `lib`). prefix: String, // Wasm bin target will generate two files in deps such as // "web-stuff.js" and "web_stuff.wasm". Note the different usages of @@ -92,60 +113,51 @@ impl TargetInfo { process.arg("--crate-type").arg(crate_type); } - let mut with_cfg = process.clone(); - with_cfg.arg("--print=sysroot"); - with_cfg.arg("--print=cfg"); + process.arg("--print=sysroot"); + process.arg("--print=cfg"); - let mut has_cfg_and_sysroot = true; let (output, error) = rustc - .cached_output(&with_cfg) - .or_else(|_| { - has_cfg_and_sysroot = false; - rustc.cached_output(&process) - }) + .cached_output(&process) .chain_err(|| "failed to run `rustc` to learn about target-specific information")?; let mut lines = output.lines(); let mut map = HashMap::new(); for crate_type in KNOWN_CRATE_TYPES { - let out = parse_crate_type(crate_type, &error, &mut lines)?; + let out = parse_crate_type(crate_type, &process, &output, &error, &mut lines)?; map.insert(crate_type.to_string(), out); } - let mut sysroot_libdir = None; - if has_cfg_and_sysroot { - let line = match lines.next() { - Some(line) => line, - None => failure::bail!( - "output of --print=sysroot missing when learning about \ - target-specific information from rustc" - ), - }; - let mut rustlib = PathBuf::from(line); - if kind == Kind::Host { + let line = match lines.next() { + Some(line) => line, + None => failure::bail!( + "output of --print=sysroot missing when learning about \ + target-specific information from rustc\n{}", + output_err_info(&process, &output, &error) + ), + }; + let mut rustlib = PathBuf::from(line); + let sysroot_libdir = match kind { + Kind::Host => { if cfg!(windows) { rustlib.push("bin"); } else { rustlib.push("lib"); } - sysroot_libdir = Some(rustlib); - } else { + rustlib + } + Kind::Target => { rustlib.push("lib"); rustlib.push("rustlib"); rustlib.push(target_triple); rustlib.push("lib"); - sysroot_libdir = Some(rustlib); + rustlib } - } - - let cfg = if has_cfg_and_sysroot { - Some(lines.map(Cfg::from_str).collect::>>()?) - } else { - None }; + let cfg = lines.map(Cfg::from_str).collect::>>()?; + Ok(TargetInfo { - crate_type_process: Some(crate_type_process), + crate_type_process, crate_types: RefCell::new(map), sysroot_libdir, // recalculate `rustflags` from above now that we have `cfg` @@ -154,7 +166,7 @@ impl TargetInfo { config, requested_target, &rustc.host, - cfg.as_ref().map(|v| v.as_ref()), + Some(&cfg), kind, "RUSTFLAGS", )?, @@ -162,7 +174,7 @@ impl TargetInfo { config, requested_target, &rustc.host, - cfg.as_ref().map(|v| v.as_ref()), + Some(&cfg), kind, "RUSTDOCFLAGS", )?, @@ -170,8 +182,8 @@ impl TargetInfo { }) } - pub fn cfg(&self) -> Option<&[Cfg]> { - self.cfg.as_ref().map(|v| v.as_ref()) + pub fn cfg(&self) -> &[Cfg] { + &self.cfg } pub fn file_types( @@ -255,21 +267,26 @@ impl TargetInfo { } fn discover_crate_type(&self, crate_type: &str) -> CargoResult> { - let mut process = self.crate_type_process.clone().unwrap(); + let mut process = self.crate_type_process.clone(); 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", + "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())?) + Ok(parse_crate_type( + crate_type, + &process, + output, + error, + &mut output.lines(), + )?) } } @@ -284,6 +301,8 @@ impl TargetInfo { // are two files for bin (`.wasm` and `.js`)). fn parse_crate_type( crate_type: &str, + cmd: &ProcessBuilder, + output: &str, error: &str, lines: &mut str::Lines<'_>, ) -> CargoResult> { @@ -297,9 +316,9 @@ fn parse_crate_type( let line = match lines.next() { Some(line) => line, None => failure::bail!( - "malformed output when learning about \ - crate-type {} information", - crate_type + "malformed output when learning about crate-type {} information\n{}", + crate_type, + output_err_info(cmd, output, error) ), }; let mut parts = line.trim().split("___"); @@ -307,14 +326,31 @@ fn parse_crate_type( let suffix = match parts.next() { Some(part) => part, None => failure::bail!( - "output of --print=file-names has changed in \ - the compiler, cannot parse" + "output of --print=file-names has changed in the compiler, cannot parse\n{}", + output_err_info(cmd, output, error) ), }; Ok(Some((prefix.to_string(), suffix.to_string()))) } +/// Helper for creating an error message when parsing rustc output fails. +fn output_err_info(cmd: &ProcessBuilder, stdout: &str, stderr: &str) -> String { + let mut result = format!("command was: {}\n", cmd); + if !stdout.is_empty() { + result.push_str("\n--- stdout\n"); + result.push_str(stdout); + } + if !stderr.is_empty() { + result.push_str("\n--- stderr\n"); + result.push_str(stderr); + } + if stdout.is_empty() && stderr.is_empty() { + result.push_str("(no output received)"); + } + result +} + /// Acquire extra flags to pass to the compiler from various locations. /// /// The locations are: diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index 5f54818b6d9..8c24c2e281b 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -46,10 +46,10 @@ pub struct Compilation<'cfg> { pub host_deps_output: PathBuf, /// The path to rustc's own libstd - pub host_dylib_path: Option, + pub host_dylib_path: PathBuf, /// The path to libstd for the target - pub target_dylib_path: Option, + pub target_dylib_path: PathBuf, /// Extra environment variables that were passed to compilations and should /// be passed to future invocations of programs. @@ -189,14 +189,14 @@ impl<'cfg> Compilation<'cfg> { ) -> CargoResult { let mut search_path = if is_host { let mut search_path = vec![self.host_deps_output.clone()]; - search_path.extend(self.host_dylib_path.clone()); + search_path.push(self.host_dylib_path.clone()); search_path } else { let mut search_path = super::filter_dynamic_search_path(self.native_dirs.iter(), &self.root_output); search_path.push(self.deps_output.clone()); search_path.push(self.root_output.clone()); - search_path.extend(self.target_dylib_path.clone()); + search_path.push(self.target_dylib_path.clone()); search_path }; @@ -286,29 +286,27 @@ fn target_runner(bcx: &BuildContext<'_, '_>) -> CargoResult) -> bool { + pub fn matches(&self, name: &str, cfg: &[Cfg]) -> bool { match *self { Platform::Name(ref p) => p == name, - Platform::Cfg(ref p) => match cfg { - Some(cfg) => p.matches(cfg), - None => false, - }, + Platform::Cfg(ref p) => p.matches(cfg), } } } diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index 060517f2c16..da47787cd3e 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -4,7 +4,6 @@ use std::collections::hash_map::{Entry, HashMap}; use std::env; use std::hash::{Hash, Hasher, SipHasher}; use std::path::{Path, PathBuf}; -use std::process::Stdio; use std::sync::Mutex; use log::{debug, info, warn}; @@ -91,10 +90,6 @@ impl Rustc { self.cache.lock().unwrap().cached_output(cmd) } - pub fn cached_success(&self, cmd: &ProcessBuilder) -> CargoResult { - self.cache.lock().unwrap().cached_success(cmd) - } - pub fn set_wrapper(&mut self, wrapper: ProcessBuilder) { self.wrapper = Some(wrapper); } @@ -135,16 +130,16 @@ impl Cache { let data = match read(&cache_location) { Ok(data) => { if data.rustc_fingerprint == rustc_fingerprint { - info!("reusing existing rustc info cache"); + debug!("reusing existing rustc info cache"); dirty = false; data } else { - info!("different compiler, creating new rustc info cache"); + debug!("different compiler, creating new rustc info cache"); empty } } Err(e) => { - info!("failed to read rustc info cache: {}", e); + debug!("failed to read rustc info cache: {}", e); empty } }; @@ -163,7 +158,7 @@ impl Cache { if let Err(e) = fingerprint { warn!("failed to calculate rustc fingerprint: {}", e); } - info!("rustc info cache disabled"); + debug!("rustc info cache disabled"); Cache { cache_location: None, dirty: false, @@ -177,11 +172,12 @@ impl Cache { let key = process_fingerprint(cmd); match self.data.outputs.entry(key) { Entry::Occupied(entry) => { - info!("rustc info cache hit"); + debug!("rustc info cache hit"); Ok(entry.get().clone()) } Entry::Vacant(entry) => { - info!("rustc info cache miss"); + debug!("rustc info cache miss"); + debug!("running {}", cmd); let output = cmd.exec_with_output()?; let stdout = String::from_utf8(output.stdout) .map_err(|_| internal("rustc didn't return utf8 output"))?; @@ -194,28 +190,6 @@ impl Cache { } } } - - fn cached_success(&mut self, cmd: &ProcessBuilder) -> CargoResult { - let key = process_fingerprint(cmd); - match self.data.successes.entry(key) { - Entry::Occupied(entry) => { - info!("rustc info cache hit"); - Ok(*entry.get()) - } - Entry::Vacant(entry) => { - info!("rustc info cache miss"); - let success = cmd - .build_command() - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status()? - .success(); - entry.insert(success); - self.dirty = true; - Ok(success) - } - } - } } impl Drop for Cache { diff --git a/tests/testsuite/rustc_info_cache.rs b/tests/testsuite/rustc_info_cache.rs index 9b1c82e6a1b..51dc4a42881 100644 --- a/tests/testsuite/rustc_info_cache.rs +++ b/tests/testsuite/rustc_info_cache.rs @@ -13,7 +13,7 @@ fn rustc_info_cache() { let update = "[..]updated rustc info cache[..]"; p.cargo("build") - .env("CARGO_LOG", "cargo::util::rustc=info") + .env("CARGO_LOG", "cargo::util::rustc=debug") .with_stderr_contains("[..]failed to read rustc info cache[..]") .with_stderr_contains(miss) .with_stderr_does_not_contain(hit) @@ -21,7 +21,7 @@ fn rustc_info_cache() { .run(); p.cargo("build") - .env("CARGO_LOG", "cargo::util::rustc=info") + .env("CARGO_LOG", "cargo::util::rustc=debug") .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(hit) .with_stderr_does_not_contain(miss) @@ -29,7 +29,7 @@ fn rustc_info_cache() { .run(); p.cargo("build") - .env("CARGO_LOG", "cargo::util::rustc=info") + .env("CARGO_LOG", "cargo::util::rustc=debug") .env("CARGO_CACHE_RUSTC_INFO", "0") .with_stderr_contains("[..]rustc info cache disabled[..]") .with_stderr_does_not_contain(update) @@ -63,7 +63,7 @@ fn rustc_info_cache() { }; p.cargo("build") - .env("CARGO_LOG", "cargo::util::rustc=info") + .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]different compiler, creating new rustc info cache[..]") .with_stderr_contains(miss) @@ -72,7 +72,7 @@ fn rustc_info_cache() { .run(); p.cargo("build") - .env("CARGO_LOG", "cargo::util::rustc=info") + .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(hit) @@ -83,7 +83,7 @@ fn rustc_info_cache() { other_rustc.move_into_the_future(); p.cargo("build") - .env("CARGO_LOG", "cargo::util::rustc=info") + .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]different compiler, creating new rustc info cache[..]") .with_stderr_contains(miss) @@ -92,7 +92,7 @@ fn rustc_info_cache() { .run(); p.cargo("build") - .env("CARGO_LOG", "cargo::util::rustc=info") + .env("CARGO_LOG", "cargo::util::rustc=debug") .env("RUSTC", other_rustc.display().to_string()) .with_stderr_contains("[..]reusing existing rustc info cache[..]") .with_stderr_contains(hit)