diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 00639978c48..d7133878d58 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -6,7 +6,6 @@ use rustc_serialize::{Encoder, Encodable}; use core::{Dependency, PackageId, PackageIdSpec, Summary}; use core::package_id::Metadata; -use util::{CargoResult, human}; /// Contains all the information about a package, as loaded from a Cargo.toml. #[derive(Clone, Debug)] @@ -44,33 +43,40 @@ pub struct ManifestMetadata { pub documentation: Option, // url } -#[derive(Debug, Clone, PartialEq, Eq, Hash, RustcEncodable, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum LibKind { Lib, Rlib, Dylib, - StaticLib + Other(String), } impl LibKind { - pub fn from_str(string: &str) -> CargoResult { + pub fn from_str(string: &str) -> LibKind { match string { - "lib" => Ok(LibKind::Lib), - "rlib" => Ok(LibKind::Rlib), - "dylib" => Ok(LibKind::Dylib), - "staticlib" => Ok(LibKind::StaticLib), - _ => Err(human(format!("crate-type \"{}\" was not one of lib|rlib|dylib|staticlib", - string))) + "lib" => LibKind::Lib, + "rlib" => LibKind::Rlib, + "dylib" => LibKind::Dylib, + s => LibKind::Other(s.to_string()), } } /// Returns the argument suitable for `--crate-type` to pass to rustc. - pub fn crate_type(&self) -> &'static str { + pub fn crate_type(&self) -> &str { match *self { LibKind::Lib => "lib", LibKind::Rlib => "rlib", LibKind::Dylib => "dylib", - LibKind::StaticLib => "staticlib" + LibKind::Other(ref s) => s, + } + } + + pub fn linkable(&self) -> bool { + match *self { + LibKind::Lib | + LibKind::Rlib | + LibKind::Dylib => true, + LibKind::Other(..) => false, } } } @@ -335,12 +341,7 @@ impl Target { pub fn linkable(&self) -> bool { match self.kind { TargetKind::Lib(ref kinds) => { - kinds.iter().any(|k| { - match *k { - LibKind::Lib | LibKind::Rlib | LibKind::Dylib => true, - LibKind::StaticLib => false, - } - }) + kinds.iter().any(|k| k.linkable()) } _ => false } @@ -353,7 +354,7 @@ impl Target { pub fn is_custom_build(&self) -> bool { self.kind == TargetKind::CustomBuild } /// Returns the arguments suitable for `--crate-type` to pass to rustc. - pub fn rustc_crate_types(&self) -> Vec<&'static str> { + pub fn rustc_crate_types(&self) -> Vec<&str> { match self.kind { TargetKind::Lib(ref kinds) => { kinds.iter().map(|kind| kind.crate_type()).collect() @@ -368,7 +369,11 @@ impl Target { pub fn can_lto(&self) -> bool { match self.kind { - TargetKind::Lib(ref v) => *v == [LibKind::StaticLib], + TargetKind::Lib(ref v) => { + !v.contains(&LibKind::Rlib) && + !v.contains(&LibKind::Dylib) && + !v.contains(&LibKind::Lib) + } _ => true, } } diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index 8b8f3cae90a..1c70176af1d 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -42,23 +42,20 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> { None => None, }; - let cx = try!(Context::new(&resolve, &packages, opts.config, - host_layout, target_layout, - BuildConfig::default(), - root.manifest().profiles())); + let mut cx = try!(Context::new(&resolve, &packages, opts.config, + host_layout, target_layout, + BuildConfig::default(), + root.manifest().profiles())); + let mut units = Vec::new(); - // resolve package specs and remove the corresponding packages for spec in opts.spec { // Translate the spec to a Package let pkgid = try!(resolve.query(spec)); let pkg = try!(packages.get(&pkgid)); - // And finally, clean everything out! + // Generate all relevant `Unit` targets for this package for target in pkg.targets() { for kind in [Kind::Host, Kind::Target].iter() { - let layout = cx.layout(&pkg, *kind); - try!(rm_rf(&layout.proxy().fingerprint(&pkg))); - try!(rm_rf(&layout.build(&pkg))); let Profiles { ref release, ref dev, ref test, ref bench, ref doc, ref custom_build, ref test_deps, ref bench_deps, @@ -66,21 +63,30 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> { let profiles = [release, dev, test, bench, doc, custom_build, test_deps, bench_deps]; for profile in profiles.iter() { - let unit = Unit { + units.push(Unit { pkg: &pkg, target: target, profile: profile, kind: *kind, - }; - let root = cx.out_dir(&unit); - for filename in try!(cx.target_filenames(&unit)).iter() { - try!(rm_rf(&root.join(&filename))); - } + }); } } } } + try!(cx.probe_target_info(&units)); + + for unit in units.iter() { + let layout = cx.layout(&unit.pkg, unit.kind); + try!(rm_rf(&layout.proxy().fingerprint(&unit.pkg))); + try!(rm_rf(&layout.build(&unit.pkg))); + + let root = cx.out_dir(&unit); + for (filename, _) in try!(cx.target_filenames(&unit)) { + try!(rm_rf(&root.join(&filename))); + } + } + Ok(()) } diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index bd5a76ba7a5..6eb5ecca92c 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -1,13 +1,12 @@ -use std::collections::{HashSet, HashMap}; +use std::collections::{HashSet, HashMap, BTreeSet}; use std::env; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use std::sync::Arc; -use regex::Regex; use core::{Package, PackageId, PackageSet, Resolve, Target, Profile}; -use core::{TargetKind, LibKind, Profiles, Metadata, Dependency}; +use core::{TargetKind, Profiles, Metadata, Dependency}; use core::dependency::Kind as DepKind; use util::{self, CargoResult, ChainError, internal, Config, profile, Cfg, human}; @@ -49,11 +48,9 @@ pub struct Context<'a, 'cfg: 'a> { profiles: &'a Profiles, } -#[derive(Clone)] +#[derive(Clone, Default)] struct TargetInfo { - dylib: Option<(String, String)>, - staticlib: Option<(String, String)>, - exe: String, + crate_types: HashMap>, cfg: Option>, } @@ -67,12 +64,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> { profiles: &'a Profiles) -> CargoResult> { let target = build_config.requested_target.clone(); let target = target.as_ref().map(|s| &s[..]); - let target_info = try!(Context::target_info(target, config, &build_config)); - let host_info = if build_config.requested_target.is_none() { - target_info.clone() - } else { - try!(Context::target_info(None, config, &build_config)) - }; let target_triple = target.unwrap_or_else(|| { &config.rustc_info().host[..] }).to_string(); @@ -86,8 +77,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> { resolve: resolve, packages: packages, config: config, - target_info: target_info, - host_info: host_info, + target_info: TargetInfo::default(), + host_info: TargetInfo::default(), compilation: Compilation::new(config), build_state: Arc::new(BuildState::new(&build_config)), build_config: build_config, @@ -101,25 +92,87 @@ impl<'a, 'cfg> Context<'a, 'cfg> { }) } - /// Run `rustc` to discover the dylib prefix/suffix for the target - /// specified as well as the exe suffix - fn target_info(target: Option<&str>, - cfg: &Config, - build_config: &BuildConfig) - -> CargoResult { - let kind = if target.is_none() {Kind::Host} else {Kind::Target}; - let mut process = util::process(cfg.rustc()); + /// Prepare this context, ensuring that all filesystem directories are in + /// place. + pub fn prepare(&mut self, root: &Package) -> CargoResult<()> { + let _p = profile::start("preparing layout"); + + try!(self.host.prepare().chain_error(|| { + internal(format!("couldn't prepare build directories")) + })); + match self.target { + Some(ref mut target) => { + try!(target.prepare().chain_error(|| { + internal(format!("couldn't prepare build directories")) + })); + } + None => {} + } + + self.compilation.root_output = + self.layout(root, Kind::Target).proxy().dest().to_path_buf(); + self.compilation.deps_output = + self.layout(root, Kind::Target).proxy().deps().to_path_buf(); + Ok(()) + } + + /// Ensure that we've collected all target-specific information to compile + /// all the units mentioned in `units`. + pub fn probe_target_info(&mut self, units: &[Unit<'a>]) -> CargoResult<()> { + let mut crate_types = BTreeSet::new(); + // pre-fill with `bin` for learning about tests (nothing may be + // explicitly `bin`) as well as `rlib` as it's the coalesced version of + // `lib` in the compiler and we're not sure which we'll see. + crate_types.insert("bin".to_string()); + crate_types.insert("rlib".to_string()); + for unit in units { + try!(self.visit_crate_type(unit, &mut crate_types)); + } + try!(self.probe_target_info_kind(&crate_types, Kind::Target)); + if self.build_config.requested_target.is_none() { + self.host_info = self.target_info.clone(); + } else { + try!(self.probe_target_info_kind(&crate_types, Kind::Host)); + } + Ok(()) + } + + fn visit_crate_type(&self, + unit: &Unit<'a>, + crate_types: &mut BTreeSet) + -> CargoResult<()> { + for target in unit.pkg.manifest().targets() { + crate_types.extend(target.rustc_crate_types().iter().map(|s| { + if *s == "lib" { + "rlib".to_string() + } else { + s.to_string() + } + })); + } + for dep in try!(self.dep_targets(&unit)) { + try!(self.visit_crate_type(&dep, crate_types)); + } + Ok(()) + } + + fn probe_target_info_kind(&mut self, + crate_types: &BTreeSet, + kind: Kind) + -> CargoResult<()> { + let mut process = util::process(self.config.rustc()); process.arg("-") .arg("--crate-name").arg("_") - .arg("--crate-type").arg("dylib") - .arg("--crate-type").arg("staticlib") - .arg("--crate-type").arg("bin") .arg("--print=file-names") - .args(&try!(rustflags_args(cfg, build_config, kind))) + .args(&try!(rustflags_args(self.config, &self.build_config, kind))) .env_remove("RUST_LOG"); - if let Some(s) = target { - process.arg("--target").arg(s); - }; + + 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 mut with_cfg = process.clone(); with_cfg.arg("--print=cfg"); @@ -136,34 +189,31 @@ impl<'a, 'cfg> Context<'a, 'cfg> { let error = str::from_utf8(&output.stderr).unwrap(); let output = str::from_utf8(&output.stdout).unwrap(); let mut lines = output.lines(); - let nodylib = Regex::new("unsupported crate type.*dylib").unwrap(); - let nostaticlib = Regex::new("unsupported crate type.*staticlib").unwrap(); - let nobin = Regex::new("unsupported crate type.*bin").unwrap(); - let dylib = if nodylib.is_match(error) { - None - } else { - let dylib_parts: Vec<&str> = lines.next().unwrap().trim() - .split('_').collect(); - assert!(dylib_parts.len() == 2, - "rustc --print-file-name output has changed"); - Some((dylib_parts[0].to_string(), dylib_parts[1].to_string())) - }; - let staticlib = if nostaticlib.is_match(error) { - None - } else { - let staticlib_parts: Vec<&str> = lines.next().unwrap().trim() - .split('_').collect(); - assert!(staticlib_parts.len() == 2, - "rustc --print-file-name output has changed"); - Some((staticlib_parts[0].to_string(), staticlib_parts[1].to_string())) - }; - - let exe = if nobin.is_match(error) { - String::new() - } else { - lines.next().unwrap().trim() - .split('_').skip(1).next().unwrap().to_string() - }; + 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(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 cfg = if has_cfg { Some(try!(lines.map(Cfg::from_str).collect())) @@ -171,36 +221,12 @@ impl<'a, 'cfg> Context<'a, 'cfg> { None }; - Ok(TargetInfo { - dylib: dylib, - staticlib: staticlib, - exe: exe, - cfg: cfg, - }) - } - - /// Prepare this context, ensuring that all filesystem directories are in - /// place. - pub fn prepare(&mut self, root: &Package) -> CargoResult<()> { - let _p = profile::start("preparing layout"); - - try!(self.host.prepare().chain_error(|| { - internal(format!("couldn't prepare build directories")) - })); - match self.target { - Some(ref mut target) => { - try!(target.prepare().chain_error(|| { - internal(format!("couldn't prepare build directories")) - })); - } - None => {} - } - - self.compilation.root_output = - self.layout(root, Kind::Target).proxy().dest().to_path_buf(); - self.compilation.deps_output = - self.layout(root, Kind::Target).proxy().deps().to_path_buf(); - + let info = match kind { + Kind::Target => &mut self.target_info, + Kind::Host => &mut self.host_info, + }; + info.crate_types = map; + info.cfg = cfg; Ok(()) } @@ -225,38 +251,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } } - /// Return the (prefix, suffix) pair for dynamic libraries. - /// - /// If `plugin` is true, the pair corresponds to the host platform, - /// otherwise it corresponds to the target platform. - fn dylib(&self, kind: Kind) -> CargoResult<(&str, &str)> { - let (triple, pair) = if kind == Kind::Host { - (&self.config.rustc_info().host, &self.host_info.dylib) - } else { - (&self.target_triple, &self.target_info.dylib) - }; - match *pair { - None => bail!("dylib outputs are not supported for {}", triple), - Some((ref s1, ref s2)) => Ok((s1, s2)), - } - } - - /// Return the (prefix, suffix) pair for static libraries. - /// - /// If `plugin` is true, the pair corresponds to the host platform, - /// otherwise it corresponds to the target platform. - pub fn staticlib(&self, kind: Kind) -> CargoResult<(&str, &str)> { - let (triple, pair) = if kind == Kind::Host { - (&self.config.rustc_info().host, &self.host_info.staticlib) - } else { - (&self.target_triple, &self.target_info.staticlib) - }; - match *pair { - None => bail!("staticlib outputs are not supported for {}", triple), - Some((ref s1, ref s2)) => Ok((s1, s2)), - } - } - /// Return the target triple which this context is targeting. pub fn target_triple(&self) -> &str { &self.target_triple @@ -304,56 +298,67 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } /// Return the filenames that the given target for the given profile will - /// generate. - pub fn target_filenames(&self, unit: &Unit) -> CargoResult> { + /// generate, along with whether you can link against that file (e.g. it's a + /// library). + pub fn target_filenames(&self, unit: &Unit) + -> CargoResult> { let stem = self.file_stem(unit); - let suffix = if unit.target.for_host() { - &self.host_info.exe + let info = if unit.target.for_host() { + &self.host_info } else { - &self.target_info.exe + &self.target_info }; let mut ret = Vec::new(); - match *unit.target.kind() { - TargetKind::Example | - TargetKind::Bin | - TargetKind::CustomBuild | - TargetKind::Bench | - TargetKind::Test => { - ret.push(format!("{}{}", stem, suffix)); - } - TargetKind::Lib(..) if unit.profile.test => { - ret.push(format!("{}{}", stem, suffix)); - } - TargetKind::Lib(ref libs) => { - for lib in libs { - match *lib { - LibKind::Dylib => { - if let Ok((prefix, suffix)) = self.dylib(unit.kind) { - ret.push(format!("{}{}{}", prefix, stem, suffix)); - } - } - LibKind::Lib | - LibKind::Rlib => ret.push(format!("lib{}.rlib", stem)), - LibKind::StaticLib => { - if let Ok((prefix, suffix)) = self.staticlib(unit.kind) { - ret.push(format!("{}{}{}", prefix, stem, suffix)); - } - } + let mut unsupported = Vec::new(); + { + 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))) => { + ret.push((format!("{}{}{}", prefix, stem, suffix), + linkable)); + Ok(()) + } + // not supported, don't worry about it + Some(&None) => { + unsupported.push(crate_type.to_string()); + Ok(()) } + None => { + bail!("failed to learn about crate-type `{}` early on", + crate_type) + } + } + }; + match *unit.target.kind() { + TargetKind::Example | + TargetKind::Bin | + TargetKind::CustomBuild | + TargetKind::Bench | + TargetKind::Test => { + try!(add("bin", false)); } - if ret.is_empty() { - if libs.contains(&LibKind::Dylib) { - bail!("cannot produce dylib for `{}` as the target `{}` \ - does not support dynamic libraries", - unit.pkg, self.target_triple) + TargetKind::Lib(..) if unit.profile.test => { + try!(add("bin", false)); + } + TargetKind::Lib(ref libs) => { + for lib in libs { + try!(add(lib.crate_type(), lib.linkable())); } - bail!("cannot compile `{}` as the target `{}` does not \ - support any of the output crate types", - unit.pkg, self.target_triple); } } } + if ret.is_empty() { + if unsupported.len() > 0 { + bail!("cannot produce {} for `{}` as the target `{}` \ + does not support these crate types", + unsupported.join(", "), unit.pkg, self.target_triple) + } + bail!("cannot compile `{}` as the target `{}` does not \ + support any of the output crate types", + unit.pkg, self.target_triple); + } Ok(ret) } diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index 042e223b3cb..437474c498e 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -63,7 +63,7 @@ pub fn prepare_target<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, missing_outputs = !root.join(unit.target.crate_name()) .join("index.html").exists(); } else { - for filename in try!(cx.target_filenames(unit)).iter() { + for (filename, _) in try!(cx.target_filenames(unit)) { missing_outputs |= fs::metadata(root.join(filename)).is_err(); } } diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index cc40730a84c..91626dccc99 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -96,6 +96,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a PackagesToBuild<'a>, let mut queue = JobQueue::new(&cx); try!(cx.prepare(root)); + try!(cx.probe_target_info(&units)); try!(custom_build::build_map(&mut cx, &units)); for unit in units.iter() { @@ -117,7 +118,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a PackagesToBuild<'a>, .or_insert(Vec::new()) .push(("OUT_DIR".to_string(), out_dir)); - for filename in try!(cx.target_filenames(unit)).iter() { + for (filename, _linkable) in try!(cx.target_filenames(unit)) { let dst = cx.out_dir(unit).join(filename); if unit.profile.test { cx.compilation.tests.push((unit.pkg.clone(), @@ -142,7 +143,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(pkg_targets: &'a PackagesToBuild<'a>, } let v = try!(cx.target_filenames(unit)); - let v = v.into_iter().map(|f| { + let v = v.into_iter().map(|(f, _)| { (unit.target.clone(), cx.out_dir(unit).join(f)) }).collect::>(); cx.compilation.libraries.insert(pkgid.clone(), v); @@ -264,7 +265,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { // FIXME(rust-lang/rust#18913): we probably shouldn't have to do // this manually - for filename in filenames.iter() { + for &(ref filename, _linkable) in filenames.iter() { let dst = root.join(filename); if fs::metadata(&dst).is_ok() { try!(fs::remove_file(&dst)); @@ -280,7 +281,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { })); if do_rename && real_name != crate_name { - let dst = root.join(&filenames[0]); + let dst = root.join(&filenames[0].0); let src = dst.with_file_name(dst.file_name().unwrap() .to_str().unwrap() .replace(&real_name, &crate_name)); @@ -587,11 +588,9 @@ fn build_deps_args(cmd: &mut CommandPrototype, cx: &Context, unit: &Unit) -> CargoResult<()> { let layout = cx.layout(unit.pkg, unit.kind); - for filename in try!(cx.target_filenames(unit)) { - if let Ok((prefix, suffix)) = cx.staticlib(unit.kind) { - if filename.starts_with(prefix) && filename.ends_with(suffix) { - continue - } + for (filename, linkable) in try!(cx.target_filenames(unit)) { + if !linkable { + continue } let mut v = OsString::new(); v.push(&unit.target.crate_name()); diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 82ea4533aca..04991a71dae 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -495,8 +495,7 @@ impl TomlManifest { &examples, &tests, &benches, - &metadata, - &mut warnings); + &metadata); if targets.is_empty() { debug!("manifest has no build targets"); @@ -867,8 +866,7 @@ fn normalize(lib: &Option, examples: &[TomlExampleTarget], tests: &[TomlTestTarget], benches: &[TomlBenchTarget], - metadata: &Metadata, - warnings: &mut Vec) -> Vec { + metadata: &Metadata) -> Vec { fn configure(toml: &TomlTarget, target: &mut Target) { let t2 = target.clone(); target.set_tested(toml.test.unwrap_or(t2.tested())) @@ -881,23 +879,12 @@ fn normalize(lib: &Option, fn lib_target(dst: &mut Vec, l: &TomlLibTarget, - metadata: &Metadata, - warnings: &mut Vec) { + metadata: &Metadata) { let path = l.path.clone().unwrap_or( PathValue::Path(Path::new("src").join(&format!("{}.rs", l.name()))) ); let crate_types = match l.crate_type.clone() { - Some(kinds) => { - // For now, merely warn about invalid crate types. - // In the future, it might be nice to make them errors. - kinds.iter().filter_map(|s| { - let kind = LibKind::from_str(s); - if let Err(ref error) = kind { - warnings.push(error.to_string()); - } - kind.ok() - }).collect() - } + Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), None => { vec![ if l.plugin == Some(true) {LibKind::Dylib} else {LibKind::Lib} ] @@ -992,7 +979,7 @@ fn normalize(lib: &Option, let mut ret = Vec::new(); if let Some(ref lib) = *lib { - lib_target(&mut ret, lib, metadata, warnings); + lib_target(&mut ret, lib, metadata); bin_targets(&mut ret, bins, &mut |bin| Path::new("src").join("bin") .join(&format!("{}.rs", bin.name()))); diff --git a/tests/bad-config.rs b/tests/bad-config.rs index b88ea2f6bfe..d456d1f21f3 100644 --- a/tests/bad-config.rs +++ b/tests/bad-config.rs @@ -271,10 +271,8 @@ fn bad_crate_type() { .file("src/lib.rs", ""); assert_that(foo.cargo_process("build").arg("-v"), - execs().with_status(0).with_stderr("\ -warning: crate-type \"bad_type\" was not one of lib|rlib|dylib|staticlib -[COMPILING] foo v0.0.0 (file:///[..]) -[RUNNING] `rustc [..] --crate-type rlib [..]` + execs().with_status(101).with_stderr_contains("\ +error: failed to run `rustc` to learn about target-specific information ")); }