From 14a28afb05b956c6e5ea0d9c706d8c60cf0a6891 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Tue, 4 Oct 2016 15:21:16 -0700 Subject: [PATCH 01/10] Add tests for feature freshness --- tests/freshness.rs | 187 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 1 deletion(-) diff --git a/tests/freshness.rs b/tests/freshness.rs index 03baf550ee5..49ab26a8c7c 100644 --- a/tests/freshness.rs +++ b/tests/freshness.rs @@ -145,7 +145,7 @@ fn rebuild_sub_package_then_while_package() { } #[test] -fn changing_features_is_ok() { +fn changing_lib_features_caches_targets() { let p = project("foo") .file("Cargo.toml", r#" [package] @@ -170,18 +170,203 @@ fn changing_features_is_ok() { .with_stderr("\ [..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +")); + + /* Targets should be cached from the first build */ + + assert_that(p.cargo("build"), + execs().with_status(0) + .with_stderr("\ +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); assert_that(p.cargo("build"), + execs().with_status(0) + .with_stdout("")); + + assert_that(p.cargo("build").arg("--features").arg("foo"), + execs().with_status(0) + .with_stderr("\ +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +")); +} + +#[test] +fn changing_bin_paths_common_target_features_caches_targets() { + /// Make sure dep_cache crate is built once per feature + let p = project("foo") + .file(".cargo/config", r#" + [build] + target-dir = "./target" + "#) + .file("dep_crate/Cargo.toml", r#" + [package] + name = "dep_crate" + version = "0.0.1" + authors = [] + + [features] + ftest = [] + "#) + .file("dep_crate/src/lib.rs", r#" + #[cfg(feature = "ftest")] + pub fn yo() { + println!("ftest on") + } + #[cfg(not(feature = "ftest"))] + pub fn yo() { + println!("ftest off") + } + "#) + .file("a/Cargo.toml", r#" + [package] + name = "a" + version = "0.0.1" + authors = [] + + [dependencies] + dep_crate = {path = "../dep_crate", features = []} + "#) + .file("a/src/lib.rs", "") + .file("a/src/main.rs", r#" + extern crate dep_crate; + use dep_crate::yo; + fn main() { + yo(); + } + "#) + .file("b/Cargo.toml", r#" + [package] + name = "b" + version = "0.0.1" + authors = [] + + [dependencies] + dep_crate = {path = "../dep_crate", features = ["ftest"]} + "#) + .file("b/src/lib.rs", "") + .file("b/src/main.rs", r#" + extern crate dep_crate; + use dep_crate::yo; + fn main() { + yo(); + } + "#); + + /* Build and rebuild a/. Ensure dep_crate only builds once */ + assert_that(p.cargo_process("run").cwd(p.root().join("a")), + execs().with_status(0) + .with_stdout("ftest off") + .with_stderr("\ +[..]Compiling dep_crate v0.0.1 ([..]) +[..]Compiling a v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `[..]target/debug/a` +")); + assert_that(p.cargo("clean").arg("-p").arg("a").cwd(p.root().join("a")), + execs().with_status(0)); + assert_that(p.cargo("run").cwd(p.root().join("a")), + execs().with_status(0) + .with_stdout("ftest off") + .with_stderr("\ +[..]Compiling a v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `[..]target/debug/a` +")); + + /* Build and rebuild b/. Ensure dep_crate only builds once */ + assert_that(p.cargo("run").cwd(p.root().join("b")), + execs().with_status(0) + .with_stdout("ftest on") + .with_stderr("\ +[..]Compiling dep_crate v0.0.1 ([..]) +[..]Compiling b v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `[..]target/debug/b` +")); + assert_that(p.cargo("clean").arg("-p").arg("b").cwd(p.root().join("b")), + execs().with_status(0)); + assert_that(p.cargo("run").cwd(p.root().join("b")), + execs().with_status(0) + .with_stdout("ftest on") + .with_stderr("\ +[..]Compiling b v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `[..]target/debug/b` +")); + + /* Build a/ package again. If we cache different feature dep builds correctly, + * this should not cause a rebuild of dep_crate */ + assert_that(p.cargo("clean").arg("-p").arg("a").cwd(p.root().join("a")), + execs().with_status(0)); + assert_that(p.cargo("run").cwd(p.root().join("a")), + execs().with_status(0) + .with_stdout("ftest off") + .with_stderr("\ +[..]Compiling a v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `[..]target/debug/a` +")); + + /* Build b/ package again. If we cache different feature dep builds correctly, + * this should not cause a rebuild */ + assert_that(p.cargo("clean").arg("-p").arg("b").cwd(p.root().join("b")), + execs().with_status(0)); + assert_that(p.cargo("run").cwd(p.root().join("b")), + execs().with_status(0) + .with_stdout("ftest on") + .with_stderr("\ +[..]Compiling b v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `[..]target/debug/b` +")); +} + +#[test] +fn changing_bin_features_caches_targets() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + authors = [] + version = "0.0.1" + + [features] + foo = [] + "#) + .file("src/main.rs", "fn main() {}"); + + assert_that(p.cargo_process("build"), + execs().with_status(0) + .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +")); + + assert_that(p.cargo("build").arg("--features").arg("foo"), execs().with_status(0) .with_stderr("\ [..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +")); + + /* Targets should be cached from the first build */ + + assert_that(p.cargo("build"), + execs().with_status(0) + .with_stderr("\ +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); assert_that(p.cargo("build"), execs().with_status(0) .with_stdout("")); + + assert_that(p.cargo("build").arg("--features").arg("foo"), + execs().with_status(0) + .with_stderr("\ +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +")); } #[test] From 530f2dd4175de80ba30ddd7555110b7b9fe7b72b Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Tue, 4 Oct 2016 16:16:30 -0700 Subject: [PATCH 02/10] Mix feature flags into fingerprint/metadata shorthash Since building dependencies results in different libraries depending on the feature flags, I added the feature flags into the short_hash. This solves an issue when multiple crates share a target directory or multiple targets share a common library with divergent feature flag choice. - Only link binaries, build scripts, and top level deps - Handle dylibs differently (no metadata filename / linking) - Fingerprint based on link_dst rather than file_stem. This (sadly) limits the effects of dep caching to things which don't produce a hard-link. Currently, this is only dependent library crates. Stil a big win. --- src/cargo/core/manifest.rs | 7 ++ src/cargo/ops/cargo_clean.rs | 8 +- src/cargo/ops/cargo_rustc/context.rs | 124 ++++++++++++++++------- src/cargo/ops/cargo_rustc/fingerprint.rs | 21 ++-- src/cargo/ops/cargo_rustc/layout.rs | 2 +- src/cargo/ops/cargo_rustc/mod.rs | 76 +++++++------- tests/bench.rs | 28 ++--- tests/build-script.rs | 6 +- tests/build.rs | 8 +- tests/clean.rs | 4 +- tests/cross-compile.rs | 4 +- tests/freshness.rs | 116 +++++++++++++++++---- tests/git.rs | 2 +- tests/path.rs | 2 +- tests/plugins.rs | 3 +- tests/run.rs | 4 +- tests/rustc.rs | 2 +- tests/test.rs | 38 +++---- 18 files changed, 301 insertions(+), 154 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 4e693ff2b3f..f5f4217da81 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -395,6 +395,13 @@ impl Target { } } + pub fn is_dylib(&self) -> bool { + match self.kind { + TargetKind::Lib(ref libs) => libs.iter().any(|l| *l == LibKind::Dylib), + _ => false + } + } + pub fn linkable(&self) -> bool { match self.kind { TargetKind::Lib(ref kinds) => { diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index 6d544c19be2..738417a4bf8 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -77,9 +77,11 @@ pub fn clean(ws: &Workspace, opts: &CleanOptions) -> CargoResult<()> { 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))); + for (src, link_dst, _) in try!(cx.target_filenames(&unit)) { + try!(rm_rf(&src)); + if let Some(dst) = link_dst { + try!(rm_rf(&dst)); + } } } diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index 4e0cf00db6a..9c4a34c48d4 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -309,11 +309,41 @@ impl<'a, 'cfg> Context<'a, 'cfg> { /// Get the metadata for a target in a specific profile pub fn target_metadata(&self, unit: &Unit) -> Option { - let metadata = unit.target.metadata(); + // No metadata for dylibs because of a couple issues + // - OSX encodes the dylib name in the executable + // - Windows rustc multiple files of which we can't easily link all of them + if !unit.profile.test && unit.target.is_dylib() { + return None; + } + + let metadata = unit.target.metadata().cloned().map(|mut m| { + if let Some(features) = self.resolve.features(unit.pkg.package_id()) { + let mut feat_vec: Vec<&String> = features.iter().collect(); + feat_vec.sort(); + for feat in feat_vec { + m.mix(feat); + } + } + m.mix(unit.profile); + m + }); + let mut pkg_metadata = { + let mut m = unit.pkg.generate_metadata(); + if let Some(features) = self.resolve.features(unit.pkg.package_id()) { + let mut feat_vec: Vec<&String> = features.iter().collect(); + feat_vec.sort(); + for feat in feat_vec { + m.mix(feat); + } + } + m.mix(unit.profile); + m + }; + if unit.target.is_lib() && unit.profile.test { // Libs and their tests are built in parallel, so we need to make // sure that their metadata is different. - metadata.cloned().map(|mut m| { + metadata.map(|mut m| { m.mix(&"test"); m }) @@ -321,37 +351,13 @@ impl<'a, 'cfg> Context<'a, 'cfg> { // Make sure that the name of this test executable doesn't // conflict with a library that has the same name and is // being tested - let mut metadata = unit.pkg.generate_metadata(); - metadata.mix(&format!("bin-{}", unit.target.name())); - Some(metadata) + pkg_metadata.mix(&format!("bin-{}", unit.target.name())); + Some(pkg_metadata) } else if unit.pkg.package_id().source_id().is_path() && !unit.profile.test { - // If we're not building a unit test but we're building a path - // dependency, then we're likely compiling the "current package" or - // some package in a workspace. In this situation we pass no - // metadata by default so we'll have predictable - // file names like `target/debug/libfoo.{a,so,rlib}` and such. - // - // Note, though, that the compiler's build system at least wants - // path dependencies to have hashes in filenames. To account for - // that we have an extra hack here which reads the - // `__CARGO_DEFAULT_METADATA` environment variable and creates a - // hash in the filename if that's present. - // - // This environment variable should not be relied on! It's basically - // just here for rustbuild. We need a more principled method of - // doing this eventually. - if unit.target.is_lib() { - env::var("__CARGO_DEFAULT_LIB_METADATA").ok().map(|meta| { - let mut metadata = unit.pkg.generate_metadata(); - metadata.mix(&meta); - metadata - }) - } else { - None - } + Some(pkg_metadata) } else { - metadata.cloned() + metadata } } @@ -360,19 +366,57 @@ impl<'a, 'cfg> Context<'a, 'cfg> { match self.target_metadata(unit) { Some(ref metadata) => format!("{}{}", unit.target.crate_name(), metadata.extra_filename), - None if unit.target.allows_underscores() => { - unit.target.name().to_string() + None => self.bin_stem(unit), + } + } + + fn bin_stem(&self, unit: &Unit) -> String { + if unit.target.allows_underscores() { + unit.target.name().to_string() + } else { + unit.target.crate_name() + } + } + + pub fn link_stem(&self, unit: &Unit) -> Option<(PathBuf, String)> { + let src_dir = self.out_dir(unit); + let bin_stem = self.bin_stem(unit); + let file_stem = self.file_stem(unit); + + // We currently only lift files up from the `deps` directory. If + // it was compiled into something like `example/` or `doc/` then + // we don't want to link it up. + if src_dir.ends_with("deps") { + // Don't lift up library dependencies + if unit.pkg.package_id() != &self.current_package && !unit.target.is_bin() { + None + } else { + Some(( + src_dir.parent().unwrap().to_owned(), + if unit.profile.test {file_stem} else {bin_stem}, + )) } - None => unit.target.crate_name(), + } else if bin_stem == file_stem { + None + } else if src_dir.ends_with("examples") { + Some((src_dir, bin_stem)) + } else if src_dir.parent().unwrap().ends_with("build") { + Some((src_dir, bin_stem)) + } else { + None } } /// Return the filenames that the given target for the given profile will - /// generate, along with whether you can link against that file (e.g. it's a - /// library). + /// generate as a list of 3-tuples (filename, link_dst, linkable) + /// filename: filename rustc compiles to. (Often has metadata suffix). + /// link_dst: Optional file to link/copy the result to (without metadata suffix) + /// linkable: Whether possible to link against file (eg it's a library) pub fn target_filenames(&self, unit: &Unit) - -> CargoResult> { + -> CargoResult, bool)>> { + let out_dir = self.out_dir(unit); let stem = self.file_stem(unit); + let link_stem = self.link_stem(unit); let info = if unit.target.for_host() { &self.host_info } else { @@ -386,8 +430,11 @@ impl<'a, 'cfg> Context<'a, 'cfg> { 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)); + let filename = out_dir.join(format!("{}{}{}", prefix, stem, suffix)); + let link_dst = link_stem.clone().map(|(ld, ls)| { + ld.join(format!("{}{}{}", prefix, ls, suffix)) + }); + ret.push((filename, link_dst, linkable)); Ok(()) } // not supported, don't worry about it @@ -429,6 +476,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { support any of the output crate types", unit.pkg, self.target_triple()); } + info!("Target filenames: {:?}", ret); Ok(ret) } diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index b16cf7f90df..a5d3e53e14a 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -49,7 +49,7 @@ pub fn prepare_target<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, let _p = profile::start(format!("fingerprint: {} / {}", unit.pkg.package_id(), unit.target.name())); let new = dir(cx, unit); - let loc = new.join(&filename(unit)); + let loc = new.join(&filename(cx, unit)); debug!("fingerprint at: {}", loc.display()); @@ -82,8 +82,11 @@ 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)) { - missing_outputs |= fs::metadata(root.join(filename)).is_err(); + for (src, link_dst, _) in try!(cx.target_filenames(unit)) { + missing_outputs |= fs::metadata(&src).is_err(); + if let Some(link_dst) = link_dst { + missing_outputs |= fs::metadata(link_dst).is_err(); + } } } @@ -529,7 +532,7 @@ pub fn dir(cx: &Context, unit: &Unit) -> PathBuf { /// Returns the (old, new) location for the dep info file of a target. pub fn dep_info_loc(cx: &Context, unit: &Unit) -> PathBuf { - dir(cx, unit).join(&format!("dep-{}", filename(unit))) + dir(cx, unit).join(&format!("dep-{}", filename(cx, unit))) } fn compare_old_fingerprint(loc: &Path, new_fingerprint: &Fingerprint) @@ -650,7 +653,13 @@ fn mtime_if_fresh(output: &Path, paths: I) -> Option } } -fn filename(unit: &Unit) -> String { +fn filename(cx: &Context, unit: &Unit) -> String { + // If there exists a link stem, we have to use that since multiple target filenames + // may hardlink to the same target stem. If there's no link, we can use the original + // file_stem (which can include a suffix) + let file_stem = cx.link_stem(unit) + .map(|(_path, stem)| stem) + .unwrap_or_else(|| cx.file_stem(unit)); let kind = match *unit.target.kind() { TargetKind::Lib(..) => "lib", TargetKind::Bin => "bin", @@ -666,7 +675,7 @@ fn filename(unit: &Unit) -> String { } else { "" }; - format!("{}{}-{}", flavor, kind, unit.target.name()) + format!("{}{}-{}", flavor, kind, file_stem) } // The dep-info files emitted by the compiler all have their listed paths diff --git a/src/cargo/ops/cargo_rustc/layout.rs b/src/cargo/ops/cargo_rustc/layout.rs index 18ae026e193..0c7723f401d 100644 --- a/src/cargo/ops/cargo_rustc/layout.rs +++ b/src/cargo/ops/cargo_rustc/layout.rs @@ -175,7 +175,7 @@ impl<'a> LayoutProxy<'a> { } else if unit.target.is_lib() { self.deps().to_path_buf() } else { - self.root().to_path_buf() + self.deps().to_path_buf() } } diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 6db0bb6f35e..82014c49323 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -110,14 +110,18 @@ pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>, .or_insert(Vec::new()) .push(("OUT_DIR".to_string(), out_dir)); - for (filename, _linkable) in try!(cx.target_filenames(unit)) { - let dst = cx.out_dir(unit).join(filename); + for (dst, link_dst, _linkable) in try!(cx.target_filenames(unit)) { + let bindst = match link_dst { + Some(link_dst) => link_dst, + None => dst.clone(), + }; + if unit.profile.test { cx.compilation.tests.push((unit.pkg.clone(), unit.target.name().to_string(), dst)); } else if unit.target.is_bin() || unit.target.is_example() { - cx.compilation.binaries.push(dst); + cx.compilation.binaries.push(bindst); } else if unit.target.is_lib() { let pkgid = unit.pkg.package_id().clone(); cx.compilation.libraries.entry(pkgid).or_insert(Vec::new()) @@ -135,8 +139,8 @@ pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>, } let v = try!(cx.target_filenames(unit)); - let v = v.into_iter().map(|(f, _)| { - (unit.target.clone(), cx.out_dir(unit).join(f)) + let v = v.into_iter().map(|(f, _, _)| { + (unit.target.clone(), f) }).collect::>(); cx.compilation.libraries.insert(pkgid.clone(), v); } @@ -228,9 +232,9 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { let do_rename = unit.target.allows_underscores() && !unit.profile.test; let real_name = unit.target.name().to_string(); let crate_name = unit.target.crate_name(); - let move_outputs_up = unit.pkg.package_id() == &cx.current_package; - let rustc_dep_info_loc = if do_rename { + // XXX(Rely on target_filenames iterator as source of truth rather than rederiving filestem) + let rustc_dep_info_loc = if do_rename && cx.target_metadata(unit).is_none() { root.join(&crate_name) } else { root.join(&cx.file_stem(unit)) @@ -257,8 +261,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { // FIXME(rust-lang/rust#18913): we probably shouldn't have to do // this manually - for &(ref filename, _linkable) in filenames.iter() { - let dst = root.join(filename); + for &(ref dst, ref _link_dst, _linkable) in filenames.iter() { if fs::metadata(&dst).is_ok() { try!(fs::remove_file(&dst).chain_error(|| { human(format!("Could not remove file: {}.", dst.display())) @@ -295,7 +298,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { })); if do_rename && real_name != crate_name { - let dst = root.join(&filenames[0].0); + let dst = &filenames[0].0; let src = dst.with_file_name(dst.file_name().unwrap() .to_str().unwrap() .replace(&real_name, &crate_name)); @@ -307,6 +310,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { } if !has_custom_args || fs::metadata(&rustc_dep_info_loc).is_ok() { + info!("Renaming dep_info {:?} to {:?}", rustc_dep_info_loc, dep_info_loc); try!(fs::rename(&rustc_dep_info_loc, &dep_info_loc).chain_error(|| { internal(format!("could not rename dep info: {:?}", rustc_dep_info_loc)) @@ -318,36 +322,30 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { // hard link our outputs out of the `deps` directory into the directory // above. This means that `cargo build` will produce binaries in // `target/debug` which one probably expects. - if move_outputs_up { - for &(ref filename, _linkable) in filenames.iter() { - let src = root.join(filename); - // This may have been a `cargo rustc` command which changes the - // output, so the source may not actually exist. - if !src.exists() { - continue - } + for (src, link_dst, _linkable) in filenames { + // This may have been a `cargo rustc` command which changes the + // output, so the source may not actually exist. + debug!("Thinking about linking {} to {:?}", src.display(), link_dst); + if !src.exists() || link_dst.is_none() { + continue + } + let dst = link_dst.unwrap(); - // We currently only lift files up from the `deps` directory. If - // it was compiled into something like `example/` or `doc/` then - // we don't want to link it up. - let src_dir = src.parent().unwrap(); - if !src_dir.ends_with("deps") { - continue - } - let dst = src_dir.parent().unwrap() - .join(src.file_name().unwrap()); - if dst.exists() { - try!(fs::remove_file(&dst).chain_error(|| { - human(format!("failed to remove: {}", dst.display())) - })); - } - try!(fs::hard_link(&src, &dst) - .or_else(|_| fs::copy(&src, &dst).map(|_| ())) - .chain_error(|| { - human(format!("failed to link or copy `{}` to `{}`", - src.display(), dst.display())) + debug!("linking {} to {}", src.display(), dst.display()); + if dst.exists() { + try!(fs::remove_file(&dst).chain_error(|| { + human(format!("failed to remove: {}", dst.display())) })); } + try!(fs::hard_link(&src, &dst) + .or_else(|err| { + debug!("hard link failed {}. falling back to fs::copy", err); + fs::copy(&src, &dst).map(|_| ()) + }) + .chain_error(|| { + human(format!("failed to link or copy `{}` to `{}`", + src.display(), dst.display())) + })); } Ok(()) @@ -658,7 +656,7 @@ fn build_deps_args(cmd: &mut ProcessBuilder, cx: &Context, unit: &Unit) fn link_to(cmd: &mut ProcessBuilder, cx: &Context, unit: &Unit) -> CargoResult<()> { - for (filename, linkable) in try!(cx.target_filenames(unit)) { + for (dst, _link_dst, linkable) in try!(cx.target_filenames(unit)) { if !linkable { continue } @@ -667,7 +665,7 @@ fn build_deps_args(cmd: &mut ProcessBuilder, cx: &Context, unit: &Unit) v.push("="); v.push(cx.out_dir(unit)); v.push(&path::MAIN_SEPARATOR.to_string()); - v.push(&filename); + v.push(&dst.file_name().unwrap()); cmd.arg("--extern").arg(&v); } Ok(()) diff --git a/tests/bench.rs b/tests/bench.rs index 7048c57890f..fdaa7160a5f 100644 --- a/tests/bench.rs +++ b/tests/bench.rs @@ -43,7 +43,7 @@ fn cargo_bench_simple() { execs().with_stderr(&format!("\ [COMPILING] foo v0.5.0 ({}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]foo-[..][EXE]", p.url())) +[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url())) .with_stdout(" running 1 test test bench_hello ... bench: [..] 0 ns/iter (+/- 0) @@ -78,7 +78,7 @@ fn bench_tarname() { .with_stderr(format!("\ [COMPILING] foo v0.0.1 ({dir}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]bin2-[..][EXE] +[RUNNING] target[/]release[/]deps[/]bin2-[..][EXE] ", dir = prj.url())) .with_stdout(" running 1 test @@ -107,7 +107,7 @@ fn cargo_bench_verbose() { [COMPILING] foo v0.5.0 ({url}) [RUNNING] `rustc src[/]foo.rs [..]` [FINISHED] release [optimized] target(s) in [..] -[RUNNING] `[..]target[/]release[/]foo-[..][EXE] hello --bench`", url = p.url())) +[RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE] hello --bench`", url = p.url())) .with_stdout(" running 1 test test bench_hello ... bench: [..] 0 ns/iter (+/- 0) @@ -190,7 +190,7 @@ test bench_hello ... ") .with_stderr_contains(format!("\ [COMPILING] foo v0.5.0 ({}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]foo-[..][EXE] +[RUNNING] target[/]release[/]deps[/]foo-[..][EXE] thread '[..]' panicked at 'assertion failed: \ `(left == right)` (left: \ `\"hello\"`, right: `\"nope\"`)', src[/]foo.rs:14 @@ -243,7 +243,7 @@ fn bench_with_lib_dep() { execs().with_stderr(&format!("\ [COMPILING] foo v0.0.1 ({}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]baz-[..][EXE] +[RUNNING] target[/]release[/]deps[/]baz-[..][EXE] [RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url())) .with_stdout(" running 1 test @@ -353,7 +353,7 @@ fn external_bench_explicit() { execs().with_stderr(&format!("\ [COMPILING] foo v0.0.1 ({}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]bench-[..][EXE] +[RUNNING] target[/]release[/]deps[/]bench-[..][EXE] [RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url())) .with_stdout(" running 1 test @@ -403,7 +403,7 @@ fn external_bench_implicit() { execs().with_stderr(&format!("\ [COMPILING] foo v0.0.1 ({}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]external-[..][EXE] +[RUNNING] target[/]release[/]deps[/]external-[..][EXE] [RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url())) .with_stdout(" running 1 test @@ -547,7 +547,7 @@ fn lib_bin_same_name() { [COMPILING] foo v0.0.1 ({}) [FINISHED] release [optimized] target(s) in [..] [RUNNING] target[/]release[/]deps[/]foo-[..][EXE] -[RUNNING] target[/]release[/]foo-[..][EXE]", p.url())) +[RUNNING] target[/]release[/]deps[/]foo-[..][EXE]", p.url())) .with_stdout(" running 1 test test [..] ... bench: [..] 0 ns/iter (+/- 0) @@ -600,7 +600,7 @@ fn lib_with_standard_name() { .with_stderr(&format!("\ [COMPILING] syntax v0.0.1 ({dir}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]bench-[..][EXE] +[RUNNING] target[/]release[/]deps[/]bench-[..][EXE] [RUNNING] target[/]release[/]deps[/]syntax-[..][EXE]", dir = p.url())) .with_stdout(" running 1 test @@ -652,7 +652,7 @@ fn lib_with_standard_name2() { .with_stderr(&format!("\ [COMPILING] syntax v0.0.1 ({dir}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] target[/]release[/]syntax-[..][EXE]", dir = p.url())) +[RUNNING] target[/]release[/]deps[/]syntax-[..][EXE]", dir = p.url())) .with_stdout(" running 1 test test bench ... bench: [..] 0 ns/iter (+/- 0) @@ -722,7 +722,7 @@ fn bench_dylib() { [RUNNING] [..] -C opt-level=3 [..] [RUNNING] [..] -C opt-level=3 [..] [FINISHED] release [optimized] target(s) in [..] -[RUNNING] `[..]target[/]release[/]bench-[..][EXE] --bench` +[RUNNING] `[..]target[/]release[/]deps[/]bench-[..][EXE] --bench` [RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE] --bench`", dir = p.url())) .with_stdout(" running 1 test @@ -744,7 +744,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured [FRESH] bar v0.0.1 ({dir}/bar) [FRESH] foo v0.0.1 ({dir}) [FINISHED] release [optimized] target(s) in [..] -[RUNNING] `[..]target[/]release[/]bench-[..][EXE] --bench` +[RUNNING] `[..]target[/]release[/]deps[/]bench-[..][EXE] --bench` [RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE] --bench`", dir = p.url())) .with_stdout(" running 1 test @@ -871,7 +871,7 @@ fn bench_with_examples() { [RUNNING] `rustc [..]` [RUNNING] `rustc [..]` [FINISHED] release [optimized] target(s) in [..] -[RUNNING] `{dir}[/]target[/]release[/]testb1-[..][EXE] --bench` +[RUNNING] `{dir}[/]target[/]release[/]deps[/]testb1-[..][EXE] --bench` [RUNNING] `{dir}[/]target[/]release[/]deps[/]testbench-[..][EXE] --bench`", dir = p.root().display(), url = p.url())) .with_stdout(" @@ -920,7 +920,7 @@ fn test_a_bench() { .with_stderr("\ [COMPILING] foo v0.1.0 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]b-[..][EXE]") +[RUNNING] target[/]debug[/]deps[/]b-[..][EXE]") .with_stdout(" running 1 test test foo ... ok diff --git a/tests/build-script.rs b/tests/build-script.rs index 53c359f22e6..e6bcef0fbe9 100644 --- a/tests/build-script.rs +++ b/tests/build-script.rs @@ -1141,7 +1141,8 @@ fn build_script_with_dynamic_native_dependency() { #[no_mangle] pub extern fn foo() {} "#); - assert_that(build.cargo_process("build"), + assert_that(build.cargo_process("build").arg("-v") + .env("RUST_LOG", "cargo::ops::cargo_rustc"), execs().with_status(0)); let foo = project("foo") @@ -1186,7 +1187,8 @@ fn build_script_with_dynamic_native_dependency() { } "#); - assert_that(foo.cargo_process("build").env("SRC", build.root()), + assert_that(foo.cargo_process("build").arg("-v").env("SRC", build.root()) + .env("RUST_LOG", "cargo::ops::cargo_rustc"), execs().with_status(0)); } diff --git a/tests/build.rs b/tests/build.rs index 2bf78d7ba7c..ac274de22a6 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -1055,7 +1055,7 @@ fn lto_build() { -C opt-level=3 \ -C lto \ -C metadata=[..] \ - --out-dir {dir}[/]target[/]release \ + --out-dir {dir}[/]target[/]release[/]deps \ --emit=dep-info,link \ -L dependency={dir}[/]target[/]release[/]deps` [FINISHED] release [optimized] target(s) in [..] @@ -1789,6 +1789,7 @@ fn example_bin_same_name() { .unwrap(); assert_that(&p.bin("foo"), is_not(existing_file())); + // We expect a file of the form bin/foo-{metadata_hash} assert_that(&p.bin("examples/foo"), existing_file()); p.cargo("test").arg("--no-run").arg("-v") @@ -1796,6 +1797,7 @@ fn example_bin_same_name() { .unwrap(); assert_that(&p.bin("foo"), is_not(existing_file())); + // We expect a file of the form bin/foo-{metadata_hash} assert_that(&p.bin("examples/foo"), existing_file()); } @@ -2162,9 +2164,9 @@ fn build_multiple_packages() { assert_that(process(&p.bin("foo")), execs().with_stdout("i am foo\n")); - let d1_path = &p.build_dir().join("debug").join("deps") + let d1_path = &p.build_dir().join("debug") .join(format!("d1{}", env::consts::EXE_SUFFIX)); - let d2_path = &p.build_dir().join("debug").join("deps") + let d2_path = &p.build_dir().join("debug") .join(format!("d2{}", env::consts::EXE_SUFFIX)); assert_that(d1_path, existing_file()); diff --git a/tests/clean.rs b/tests/clean.rs index 59170ed708b..39cc5287203 100644 --- a/tests/clean.rs +++ b/tests/clean.rs @@ -80,9 +80,9 @@ fn clean_multiple_packages() { .arg("-p").arg("foo"), execs().with_status(0)); - let d1_path = &p.build_dir().join("debug").join("deps") + let d1_path = &p.build_dir().join("debug") .join(format!("d1{}", env::consts::EXE_SUFFIX)); - let d2_path = &p.build_dir().join("debug").join("deps") + let d2_path = &p.build_dir().join("debug") .join(format!("d2{}", env::consts::EXE_SUFFIX)); diff --git a/tests/cross-compile.rs b/tests/cross-compile.rs index d5db5635263..bbb534f8d3d 100644 --- a/tests/cross-compile.rs +++ b/tests/cross-compile.rs @@ -359,7 +359,7 @@ fn linker_and_ar() { [COMPILING] foo v0.5.0 ({url}) [RUNNING] `rustc src[/]foo.rs --crate-name foo --crate-type bin -g \ -C metadata=[..] \ - --out-dir {dir}[/]target[/]{target}[/]debug \ + --out-dir {dir}[/]target[/]{target}[/]debug[/]deps \ --emit=dep-info,link \ --target {target} \ -C ar=my-ar-tool -C linker=my-linker-tool \ @@ -473,7 +473,7 @@ fn cross_tests() { .with_stderr(&format!("\ [COMPILING] foo v0.0.0 ({foo}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]{triple}[/]debug[/]bar-[..][EXE] +[RUNNING] target[/]{triple}[/]debug[/]deps[/]bar-[..][EXE] [RUNNING] target[/]{triple}[/]debug[/]deps[/]foo-[..][EXE]", foo = p.url(), triple = target)) .with_stdout(" running 1 test diff --git a/tests/freshness.rs b/tests/freshness.rs index 49ab26a8c7c..786aef22275 100644 --- a/tests/freshness.rs +++ b/tests/freshness.rs @@ -172,11 +172,17 @@ fn changing_lib_features_caches_targets() { [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); - /* Targets should be cached from the first build */ + /* Targets should be cached from the first build + XXX Sadly these cannot be cached since the "symlink" step is + not separate from the "compile" step. Packages which link + to top level binaries eg (deps/foo-abc123 -> foo) are forced + to do an extra recompile here. + */ assert_that(p.cargo("build"), execs().with_status(0) .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); @@ -187,13 +193,71 @@ fn changing_lib_features_caches_targets() { assert_that(p.cargo("build").arg("--features").arg("foo"), execs().with_status(0) .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); } +#[test] +fn changing_profiles_caches_targets() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + authors = [] + version = "0.0.1" + + [profile.dev] + panic = "abort" + + [profile.test] + panic = "unwind" + "#) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build"), + execs().with_status(0) + .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +")); + + assert_that(p.cargo("test"), + execs().with_status(0) + .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] target[..]debug[..]deps[..]foo-[..][EXE] +[DOCTEST] foo +")); + + /* Targets should be cached from the first build + XXX Sadly these cannot be cached since the "symlink" step is + not separate from the "compile" step. Packages which link + to top level binaries eg (deps/foo-abc123 -> foo) are forced + to do an extra recompile here. + */ + + assert_that(p.cargo("build"), + execs().with_status(0) + .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +")); + + assert_that(p.cargo("test").arg("foo"), + execs().with_status(0) + .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] target[..]debug[..]deps[..]foo-[..][EXE] +[DOCTEST] foo +")); +} + #[test] fn changing_bin_paths_common_target_features_caches_targets() { - /// Make sure dep_cache crate is built once per feature + // Make sure dep_cache crate is built once per feature let p = project("foo") .file(".cargo/config", r#" [build] @@ -261,7 +325,7 @@ fn changing_bin_paths_common_target_features_caches_targets() { [..]Compiling dep_crate v0.0.1 ([..]) [..]Compiling a v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] `[..]target/debug/a` +[RUNNING] `[..]target[/]debug[/]a[EXE]` ")); assert_that(p.cargo("clean").arg("-p").arg("a").cwd(p.root().join("a")), execs().with_status(0)); @@ -271,7 +335,7 @@ fn changing_bin_paths_common_target_features_caches_targets() { .with_stderr("\ [..]Compiling a v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] `[..]target/debug/a` +[RUNNING] `[..]target[/]debug[/]a[EXE]` ")); /* Build and rebuild b/. Ensure dep_crate only builds once */ @@ -282,7 +346,7 @@ fn changing_bin_paths_common_target_features_caches_targets() { [..]Compiling dep_crate v0.0.1 ([..]) [..]Compiling b v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] `[..]target/debug/b` +[RUNNING] `[..]target[/]debug[/]b[EXE]` ")); assert_that(p.cargo("clean").arg("-p").arg("b").cwd(p.root().join("b")), execs().with_status(0)); @@ -292,7 +356,7 @@ fn changing_bin_paths_common_target_features_caches_targets() { .with_stderr("\ [..]Compiling b v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] `[..]target/debug/b` +[RUNNING] `[..]target[/]debug[/]b[EXE]` ")); /* Build a/ package again. If we cache different feature dep builds correctly, @@ -305,7 +369,7 @@ fn changing_bin_paths_common_target_features_caches_targets() { .with_stderr("\ [..]Compiling a v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] `[..]target/debug/a` +[RUNNING] `[..]target[/]debug[/]a[EXE]` ")); /* Build b/ package again. If we cache different feature dep builds correctly, @@ -318,7 +382,7 @@ fn changing_bin_paths_common_target_features_caches_targets() { .with_stderr("\ [..]Compiling b v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] `[..]target/debug/b` +[RUNNING] `[..]target[/]debug[/]b[EXE]` ")); } @@ -334,38 +398,54 @@ fn changing_bin_features_caches_targets() { [features] foo = [] "#) - .file("src/main.rs", "fn main() {}"); + .file("src/main.rs", r#" + fn main() { + let msg = if cfg!(feature = "foo") { "feature on" } else { "feature off" }; + println!("{}", msg); + } + "#); - assert_that(p.cargo_process("build"), + assert_that(p.cargo_process("run"), execs().with_status(0) + .with_stdout("feature off") .with_stderr("\ [..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `target[/]debug[/]foo[EXE]` ")); - assert_that(p.cargo("build").arg("--features").arg("foo"), + assert_that(p.cargo("run").arg("--features").arg("foo"), execs().with_status(0) + .with_stdout("feature on") .with_stderr("\ [..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `target[/]debug[/]foo[EXE]` ")); - /* Targets should be cached from the first build */ + /* Targets should be cached from the first build + XXX Sadly these cannot be cached since the "symlink" step is + not separate from the "compile" step. Packages which link + to top level binaries eg (deps/foo-abc123 -> foo) are forced + to do an extra recompile here. + */ - assert_that(p.cargo("build"), + assert_that(p.cargo("run"), execs().with_status(0) + .with_stdout("feature off") .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `target[/]debug[/]foo[EXE]` ")); - assert_that(p.cargo("build"), - execs().with_status(0) - .with_stdout("")); - - assert_that(p.cargo("build").arg("--features").arg("foo"), + assert_that(p.cargo("run").arg("--features").arg("foo"), execs().with_status(0) + .with_stdout("feature on") .with_stderr("\ +[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +[RUNNING] `target[/]debug[/]foo[EXE]` ")); } diff --git a/tests/git.rs b/tests/git.rs index 02c42b3ff7f..c60076f62f4 100644 --- a/tests/git.rs +++ b/tests/git.rs @@ -1035,7 +1035,7 @@ fn dev_deps_with_testing() { [COMPILING] [..] v0.5.0 ([..]) [COMPILING] [..] v0.5.0 ([..] [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]foo-[..][EXE]") +[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]") .with_stdout(" running 1 test test tests::foo ... ok diff --git a/tests/path.rs b/tests/path.rs index b9c89b1d10e..7d057ae75b6 100644 --- a/tests/path.rs +++ b/tests/path.rs @@ -189,7 +189,7 @@ fn cargo_compile_with_root_dev_deps_with_testing() { [COMPILING] [..] v0.5.0 ([..]) [COMPILING] [..] v0.5.0 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]foo-[..][EXE]") +[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]") .with_stdout(" running 0 tests diff --git a/tests/plugins.rs b/tests/plugins.rs index cd762377ab9..8ad26ba3678 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -147,8 +147,7 @@ fn plugin_with_dynamic_native_dependency() { fn main() { let src = PathBuf::from(env::var("SRC").unwrap()); - println!("cargo:rustc-flags=-L {}/deps", src.parent().unwrap() - .display()); + println!("cargo:rustc-flags=-L {}/deps", src.parent().unwrap().display()); } "#) .file("bar/src/lib.rs", r#" diff --git a/tests/run.rs b/tests/run.rs index 14607613866..ce007bef645 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -429,7 +429,7 @@ fn example_with_release_flag() { --out-dir {dir}[/]target[/]release[/]examples \ --emit=dep-info,link \ -L dependency={dir}[/]target[/]release[/]deps \ - --extern bar={dir}[/]target[/]release[/]deps[/]libbar.rlib` + --extern bar={dir}[/]target[/]release[/]deps[/]libbar-[..].rlib` [FINISHED] release [optimized] target(s) in [..] [RUNNING] `target[/]release[/]examples[/]a[EXE]` ", @@ -457,7 +457,7 @@ fast2")); --out-dir {dir}[/]target[/]debug[/]examples \ --emit=dep-info,link \ -L dependency={dir}[/]target[/]debug[/]deps \ - --extern bar={dir}[/]target[/]debug[/]deps[/]libbar.rlib` + --extern bar={dir}[/]target[/]debug[/]deps[/]libbar-[..].rlib` [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] `target[/]debug[/]examples[/]a[EXE]` ", diff --git a/tests/rustc.rs b/tests/rustc.rs index 5e54bae5a6e..b8475e16f44 100644 --- a/tests/rustc.rs +++ b/tests/rustc.rs @@ -97,7 +97,7 @@ fn build_main_and_allow_unstable_options() { --out-dir [..] \ --emit=dep-info,link \ -L dependency={dir}[/]target[/]debug[/]deps \ - --extern {name}={dir}[/]target[/]debug[/]deps[/]lib{name}.rlib` + --extern {name}={dir}[/]target[/]debug[/]deps[/]lib{name}-[..].rlib` [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ", dir = p.root().display(), url = p.url(), diff --git a/tests/test.rs b/tests/test.rs index b3ca52f8ce9..a9f78b2be40 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -40,7 +40,7 @@ fn cargo_test_simple() { execs().with_stderr(format!("\ [COMPILING] foo v0.5.0 ({}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]foo-[..][EXE]", p.url())) +[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE]", p.url())) .with_stdout(" running 1 test test test_hello ... ok @@ -93,7 +93,7 @@ fn cargo_test_release() { [RUNNING] [..] -C opt-level=3 [..] [FINISHED] release [optimized] target(s) in [..] [RUNNING] `[..]target[/]release[/]deps[/]foo-[..][EXE]` -[RUNNING] `[..]target[/]release[/]test-[..][EXE]` +[RUNNING] `[..]target[/]release[/]deps[/]test-[..][EXE]` [DOCTEST] foo [RUNNING] `rustdoc --test [..]lib.rs[..]`", dir = p.url())) .with_stdout(" @@ -130,7 +130,7 @@ fn cargo_test_verbose() { [COMPILING] foo v0.5.0 ({url}) [RUNNING] `rustc src[/]foo.rs [..]` [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] `[..]target[/]debug[/]foo-[..][EXE] hello`", url = p.url())) +[RUNNING] `[..]target[/]debug[/]deps[/]foo-[..][EXE] hello`", url = p.url())) .with_stdout(" running 1 test test test_hello ... ok @@ -198,7 +198,7 @@ fn cargo_test_failing_test() { execs().with_stderr(format!("\ [COMPILING] foo v0.5.0 ({url}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]foo-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] [ERROR] test failed", url = p.url())) .with_stdout_contains(" running 1 test @@ -258,7 +258,7 @@ fn test_with_lib_dep() { execs().with_stderr(format!("\ [COMPILING] foo v0.0.1 ({}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]baz-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]baz-[..][EXE] [RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] [DOCTEST] foo", p.url())) .with_stdout(" @@ -375,7 +375,7 @@ fn external_test_explicit() { [COMPILING] foo v0.0.1 ({}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] -[RUNNING] target[/]debug[/]test-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]test-[..][EXE] [DOCTEST] foo", p.url())) .with_stdout(" running 1 test @@ -423,7 +423,7 @@ fn external_test_implicit() { execs().with_stderr(format!("\ [COMPILING] foo v0.0.1 ({}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]external-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]external-[..][EXE] [RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] [DOCTEST] foo", p.url())) .with_stdout(" @@ -568,7 +568,7 @@ fn lib_bin_same_name() { [COMPILING] foo v0.0.1 ({}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] -[RUNNING] target[/]debug[/]foo-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] [DOCTEST] foo", p.url())) .with_stdout(" running 1 test @@ -621,7 +621,7 @@ fn lib_with_standard_name() { [COMPILING] syntax v0.0.1 ({dir}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] target[/]debug[/]deps[/]syntax-[..][EXE] -[RUNNING] target[/]debug[/]test-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]test-[..][EXE] [DOCTEST] syntax", dir = p.url())) .with_stdout(" running 1 test @@ -675,7 +675,7 @@ fn lib_with_standard_name2() { .with_stderr(&format!("\ [COMPILING] syntax v0.0.1 ({dir}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]syntax-[..][EXE]", dir = p.url())) +[RUNNING] target[/]debug[/]deps[/]syntax-[..][EXE]", dir = p.url())) .with_stdout(" running 1 test test test ... ok @@ -715,7 +715,7 @@ fn lib_without_name() { .with_stderr(&format!("\ [COMPILING] syntax v0.0.1 ({dir}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]syntax-[..][EXE]", dir = p.url())) +[RUNNING] target[/]debug[/]deps[/]syntax-[..][EXE]", dir = p.url())) .with_stdout(" running 1 test test test ... ok @@ -974,7 +974,7 @@ fn test_dylib() { [COMPILING] foo v0.0.1 ({dir}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] -[RUNNING] target[/]debug[/]test-[..][EXE]", dir = p.url())) +[RUNNING] target[/]debug[/]deps[/]test-[..][EXE]", dir = p.url())) .with_stdout(" running 1 test test foo ... ok @@ -994,7 +994,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured .with_stderr("\ [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] -[RUNNING] target[/]debug[/]test-[..][EXE]") +[RUNNING] target[/]debug[/]deps[/]test-[..][EXE]") .with_stdout(" running 1 test test foo ... ok @@ -1154,7 +1154,7 @@ fn test_run_specific_bin_target() { .with_stderr(format!("\ [COMPILING] foo v0.0.1 ({dir}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]bin2-[..][EXE]", dir = prj.url())) +[RUNNING] target[/]debug[/]deps[/]bin2-[..][EXE]", dir = prj.url())) .with_stdout(" running 1 test test test2 ... ok @@ -1183,7 +1183,7 @@ fn test_run_specific_test_target() { .with_stderr(format!("\ [COMPILING] foo v0.0.1 ({dir}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]b-[..][EXE]", dir = prj.url())) +[RUNNING] target[/]debug[/]deps[/]b-[..][EXE]", dir = prj.url())) .with_stdout(" running 1 test test test_b ... ok @@ -1219,7 +1219,7 @@ fn test_no_harness() { .with_stderr(&format!("\ [COMPILING] foo v0.0.1 ({dir}) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]bar-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]bar-[..][EXE] ", dir = p.url()))); } @@ -1746,7 +1746,7 @@ fn filter_no_doc_tests() { execs().with_stderr("\ [COMPILING] foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] -[RUNNING] target[/]debug[/]foo[..][EXE]") +[RUNNING] target[/]debug[/]deps[/]foo[..][EXE]") .with_stdout(" running 0 tests @@ -1944,7 +1944,7 @@ fn no_fail_fast() { [COMPILING] foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] target[/]debug[/]deps[/]foo-[..][EXE] -[RUNNING] target[/]debug[/]test_add_one-[..][EXE]") +[RUNNING] target[/]debug[/]deps[/]test_add_one-[..][EXE]") .with_stdout_contains(" running 0 tests @@ -1952,7 +1952,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured ") .with_stderr_contains("\ -[RUNNING] target[/]debug[/]test_sub_one-[..][EXE] +[RUNNING] target[/]debug[/]deps[/]test_sub_one-[..][EXE] [DOCTEST] foo") .with_stdout_contains("\ test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured From 76ff7baa58a6f4c3209b06431299d22ec02dd052 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Sat, 12 Nov 2016 00:26:39 -0800 Subject: [PATCH 03/10] Link targets in the FRESH step as well --- src/cargo/ops/cargo_rustc/context.rs | 11 +++- src/cargo/ops/cargo_rustc/fingerprint.rs | 14 ++--- src/cargo/ops/cargo_rustc/layout.rs | 2 - src/cargo/ops/cargo_rustc/mod.rs | 74 ++++++++++++++---------- tests/freshness.rs | 27 +-------- 5 files changed, 62 insertions(+), 66 deletions(-) diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index 9c4a34c48d4..4359cbc14a9 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -361,7 +361,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } } - /// Returns the file stem for a given target/profile combo + /// Returns the file stem for a given target/profile combo (with metadata) pub fn file_stem(&self, unit: &Unit) -> String { match self.target_metadata(unit) { Some(ref metadata) => format!("{}{}", unit.target.crate_name(), @@ -370,6 +370,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } } + /// Returns the bin stem for a given target (without metadata) fn bin_stem(&self, unit: &Unit) -> String { if unit.target.allows_underscores() { unit.target.name().to_string() @@ -378,6 +379,14 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } } + /// Returns a tuple with the directory and name of the hard link we expect + /// our target to be copied to. Eg, file_stem may be out_dir/deps/foo-abcdef + /// and link_stem would be out_dir/foo + /// This function returns it in two parts so the caller can add prefix/suffis + /// to filename separately + + /// Returns an Option because in some cases we don't want to link + /// (eg a dependent lib) pub fn link_stem(&self, unit: &Unit) -> Option<(PathBuf, String)> { let src_dir = self.out_dir(unit); let bin_stem = self.bin_stem(unit); diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index a5d3e53e14a..1f785609fd5 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -83,9 +83,9 @@ pub fn prepare_target<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, .join("index.html").exists(); } else { for (src, link_dst, _) in try!(cx.target_filenames(unit)) { - missing_outputs |= fs::metadata(&src).is_err(); + missing_outputs |= !src.exists(); if let Some(link_dst) = link_dst { - missing_outputs |= fs::metadata(link_dst).is_err(); + missing_outputs |= !link_dst.exists(); } } } @@ -654,12 +654,10 @@ fn mtime_if_fresh(output: &Path, paths: I) -> Option } fn filename(cx: &Context, unit: &Unit) -> String { - // If there exists a link stem, we have to use that since multiple target filenames - // may hardlink to the same target stem. If there's no link, we can use the original - // file_stem (which can include a suffix) - let file_stem = cx.link_stem(unit) - .map(|(_path, stem)| stem) - .unwrap_or_else(|| cx.file_stem(unit)); + // file_stem includes metadata hash. Thus we have a different + // fingerprint for every metadata hash version. This works because + // even if the package is fresh, we'll still link the fresh target + let file_stem = cx.file_stem(unit); let kind = match *unit.target.kind() { TargetKind::Lib(..) => "lib", TargetKind::Bin => "bin", diff --git a/src/cargo/ops/cargo_rustc/layout.rs b/src/cargo/ops/cargo_rustc/layout.rs index 0c7723f401d..393b3defd08 100644 --- a/src/cargo/ops/cargo_rustc/layout.rs +++ b/src/cargo/ops/cargo_rustc/layout.rs @@ -172,8 +172,6 @@ impl<'a> LayoutProxy<'a> { self.build(unit.pkg) } else if unit.target.is_example() { self.examples().to_path_buf() - } else if unit.target.is_lib() { - self.deps().to_path_buf() } else { self.deps().to_path_buf() } diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 82014c49323..435f28f5c2e 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -190,7 +190,11 @@ fn compile<'a, 'cfg: 'a>(cx: &mut Context<'a, 'cfg>, } else { try!(rustc(cx, unit)) }; - let dirty = work.then(dirty); + let link_work1 = try!(link_targets(cx, unit)); + let link_work2 = try!(link_targets(cx, unit)); + // Need to link targets on both the dirty and fresh + let dirty = work.then(link_work1).then(dirty); + let fresh = link_work2.then(fresh); (dirty, fresh, freshness) }; try!(jobs.enqueue(cx, unit, Job::new(dirty, fresh), freshness)); @@ -318,36 +322,6 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { try!(fingerprint::append_current_dir(&dep_info_loc, &cwd)); } - // If we're a "root crate", e.g. the target of this compilation, then we - // hard link our outputs out of the `deps` directory into the directory - // above. This means that `cargo build` will produce binaries in - // `target/debug` which one probably expects. - for (src, link_dst, _linkable) in filenames { - // This may have been a `cargo rustc` command which changes the - // output, so the source may not actually exist. - debug!("Thinking about linking {} to {:?}", src.display(), link_dst); - if !src.exists() || link_dst.is_none() { - continue - } - let dst = link_dst.unwrap(); - - debug!("linking {} to {}", src.display(), dst.display()); - if dst.exists() { - try!(fs::remove_file(&dst).chain_error(|| { - human(format!("failed to remove: {}", dst.display())) - })); - } - try!(fs::hard_link(&src, &dst) - .or_else(|err| { - debug!("hard link failed {}. falling back to fs::copy", err); - fs::copy(&src, &dst).map(|_| ()) - }) - .chain_error(|| { - human(format!("failed to link or copy `{}` to `{}`", - src.display(), dst.display())) - })); - } - Ok(()) })); @@ -381,6 +355,44 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { } } +/// Link the compiled target (often of form foo-{metadata_hash}) to the +/// final target. This must happen during both "Fresh" and "Compile" +fn link_targets(cx: &mut Context, unit: &Unit) -> CargoResult { + let filenames = try!(cx.target_filenames(unit)); + Ok(Work::new(move |_| { + // If we're a "root crate", e.g. the target of this compilation, then we + // hard link our outputs out of the `deps` directory into the directory + // above. This means that `cargo build` will produce binaries in + // `target/debug` which one probably expects. + for (src, link_dst, _linkable) in filenames { + // This may have been a `cargo rustc` command which changes the + // output, so the source may not actually exist. + debug!("Thinking about linking {} to {:?}", src.display(), link_dst); + if !src.exists() || link_dst.is_none() { + continue + } + let dst = link_dst.unwrap(); + + debug!("linking {} to {}", src.display(), dst.display()); + if dst.exists() { + try!(fs::remove_file(&dst).chain_error(|| { + human(format!("failed to remove: {}", dst.display())) + })); + } + try!(fs::hard_link(&src, &dst) + .or_else(|err| { + debug!("hard link failed {}. falling back to fs::copy", err); + fs::copy(&src, &dst).map(|_| ()) + }) + .chain_error(|| { + human(format!("failed to link or copy `{}` to `{}`", + src.display(), dst.display())) + })); + } + Ok(()) + })) +} + fn load_build_deps(cx: &Context, unit: &Unit) -> Option> { cx.build_scripts.get(unit).cloned() } diff --git a/tests/freshness.rs b/tests/freshness.rs index 786aef22275..1a51f2e69b8 100644 --- a/tests/freshness.rs +++ b/tests/freshness.rs @@ -172,17 +172,11 @@ fn changing_lib_features_caches_targets() { [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); - /* Targets should be cached from the first build - XXX Sadly these cannot be cached since the "symlink" step is - not separate from the "compile" step. Packages which link - to top level binaries eg (deps/foo-abc123 -> foo) are forced - to do an extra recompile here. - */ + /* Targets should be cached from the first build */ assert_that(p.cargo("build"), execs().with_status(0) .with_stderr("\ -[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); @@ -193,7 +187,6 @@ fn changing_lib_features_caches_targets() { assert_that(p.cargo("build").arg("--features").arg("foo"), execs().with_status(0) .with_stderr("\ -[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); } @@ -231,24 +224,17 @@ fn changing_profiles_caches_targets() { [DOCTEST] foo ")); - /* Targets should be cached from the first build - XXX Sadly these cannot be cached since the "symlink" step is - not separate from the "compile" step. Packages which link - to top level binaries eg (deps/foo-abc123 -> foo) are forced - to do an extra recompile here. - */ + /* Targets should be cached from the first build */ assert_that(p.cargo("build"), execs().with_status(0) .with_stderr("\ -[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ")); assert_that(p.cargo("test").arg("foo"), execs().with_status(0) .with_stderr("\ -[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] target[..]debug[..]deps[..]foo-[..][EXE] [DOCTEST] foo @@ -423,18 +409,12 @@ fn changing_bin_features_caches_targets() { [RUNNING] `target[/]debug[/]foo[EXE]` ")); - /* Targets should be cached from the first build - XXX Sadly these cannot be cached since the "symlink" step is - not separate from the "compile" step. Packages which link - to top level binaries eg (deps/foo-abc123 -> foo) are forced - to do an extra recompile here. - */ + /* Targets should be cached from the first build */ assert_that(p.cargo("run"), execs().with_status(0) .with_stdout("feature off") .with_stderr("\ -[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] `target[/]debug[/]foo[EXE]` ")); @@ -443,7 +423,6 @@ fn changing_bin_features_caches_targets() { execs().with_status(0) .with_stdout("feature on") .with_stderr("\ -[..]Compiling foo v0.0.1 ([..]) [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] [RUNNING] `target[/]debug[/]foo[EXE]` ")); From 4650194d207126abcf199ecab8347b985688c162 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Sat, 12 Nov 2016 18:55:07 -0800 Subject: [PATCH 04/10] Added back __CARGO_DEFAULT_LIB_METADATA handling with comment + test --- src/cargo/ops/cargo_rustc/context.rs | 22 ++++++- tests/build.rs | 86 ++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index 4359cbc14a9..a1552d63654 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -308,11 +308,31 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } /// Get the metadata for a target in a specific profile + /// We build to the path: "{filename}-{target_metadata}" + /// We use a linking step to link/copy to a predictable filename + /// like `target/debug/libfoo.{a,so,rlib}` and such. pub fn target_metadata(&self, unit: &Unit) -> Option { // No metadata for dylibs because of a couple issues // - OSX encodes the dylib name in the executable // - Windows rustc multiple files of which we can't easily link all of them - if !unit.profile.test && unit.target.is_dylib() { + // + // Two expeptions + // 1) Upstream dependencies (we aren't exporting + need to resolve name conflict) + // 2) __CARGO_DEFAULT_LIB_METADATA env var + // + // Note, though, that the compiler's build system at least wants + // path dependencies (eg libstd) to have hashes in filenames. To account for + // that we have an extra hack here which reads the + // `__CARGO_DEFAULT_METADATA` environment variable and creates a + // hash in the filename if that's present. + // + // This environment variable should not be relied on! It's + // just here for rustbuild. We need a more principled method + // doing this eventually. + if !unit.profile.test && + unit.target.is_dylib() && + unit.pkg.package_id().source_id().is_path() && + !env::var("__CARGO_DEFAULT_LIB_METADATA").is_ok() { return None; } diff --git a/tests/build.rs b/tests/build.rs index ac274de22a6..decfa8ed52e 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -417,6 +417,8 @@ fn cargo_compile_with_nested_deps_inferred() { .unwrap(); assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.bin("libbar.rlib"), is_not(existing_file())); + assert_that(&p.bin("libbaz.rlib"), is_not(existing_file())); assert_that( process(&p.bin("foo")), @@ -476,6 +478,8 @@ fn cargo_compile_with_nested_deps_correct_bin() { .unwrap(); assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.bin("libbar.rlib"), is_not(existing_file())); + assert_that(&p.bin("libbaz.rlib"), is_not(existing_file())); assert_that( process(&p.bin("foo")), @@ -544,6 +548,8 @@ fn cargo_compile_with_nested_deps_shorthand() { .unwrap(); assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.bin("libbar.rlib"), is_not(existing_file())); + assert_that(&p.bin("libbaz.rlib"), is_not(existing_file())); assert_that( process(&p.bin("foo")), @@ -612,6 +618,8 @@ fn cargo_compile_with_nested_deps_longhand() { assert_that(p.cargo_process("build"), execs()); assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.bin("libbar.rlib"), is_not(existing_file())); + assert_that(&p.bin("libbaz.rlib"), is_not(existing_file())); assert_that(process(&p.bin("foo")), execs().with_stdout("test passed\n")); @@ -754,6 +762,84 @@ fn ignores_carriage_return_in_lockfile() { execs().with_status(0)); } +#[test] +fn cargo_default_env_metadata_env_var() { + // Ensure that path dep + dylib + env_var get metadata + // (even though path_dep + dylib should not) + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.bar] + path = "bar" + "#) + .file("src/lib.rs", "// hi") + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + + [lib] + name = "bar" + crate_type = ["dylib"] + "#) + .file("bar/src/lib.rs", "// hello"); + + // No metadata on libbar since it's a dylib path dependency + assert_that(p.cargo_process("build").arg("-v"), + execs().with_status(0).with_stderr(&format!("\ +[COMPILING] bar v0.0.1 ({url}[/]bar) +[RUNNING] `rustc bar[/]src[/]lib.rs --crate-name bar --crate-type dylib \ + -C prefer-dynamic -g \ + -C metadata=[..] \ + --out-dir [..] \ + --emit=dep-info,link \ + -L dependency={dir}[/]target[/]debug[/]deps` +[COMPILING] foo v0.0.1 ({url}) +[RUNNING] `rustc src[/]lib.rs --crate-name foo --crate-type lib -g \ + -C metadata=[..] \ + -C extra-filename=[..] \ + --out-dir [..] \ + --emit=dep-info,link \ + -L dependency={dir}[/]target[/]debug[/]deps \ + --extern bar={dir}[/]target[/]debug[/]deps[/]libbar.dylib` +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +", +dir = p.root().display(), +url = p.url(), +))); + + assert_that(p.cargo_process("clean"), execs().with_status(0)); + + // If you set the env-var, then we expect metadata on libbar + assert_that(p.cargo_process("build").arg("-v").env("__CARGO_DEFAULT_LIB_METADATA", "1"), + execs().with_status(0).with_stderr(&format!("\ +[COMPILING] bar v0.0.1 ({url}[/]bar) +[RUNNING] `rustc bar[/]src[/]lib.rs --crate-name bar --crate-type dylib \ + -C prefer-dynamic -g \ + -C metadata=[..] \ + --out-dir [..] \ + --emit=dep-info,link \ + -L dependency={dir}[/]target[/]debug[/]deps` +[COMPILING] foo v0.0.1 ({url}) +[RUNNING] `rustc src[/]lib.rs --crate-name foo --crate-type lib -g \ + -C metadata=[..] \ + -C extra-filename=[..] \ + --out-dir [..] \ + --emit=dep-info,link \ + -L dependency={dir}[/]target[/]debug[/]deps \ + --extern bar={dir}[/]target[/]debug[/]deps[/]libbar-[..].dylib` +[FINISHED] debug [unoptimized + debuginfo] target(s) in [..] +", +dir = p.root().display(), +url = p.url(), +))); +} + #[test] fn crate_env_vars() { let p = project("foo") From ef049ba7ffbfb852ce0ea2d7b8760202a8e7e134 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Sat, 12 Nov 2016 19:27:09 -0800 Subject: [PATCH 05/10] Fix [/] for windows on env_metadata test --- tests/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/build.rs b/tests/build.rs index decfa8ed52e..344b960eba7 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -792,7 +792,7 @@ fn cargo_default_env_metadata_env_var() { // No metadata on libbar since it's a dylib path dependency assert_that(p.cargo_process("build").arg("-v"), execs().with_status(0).with_stderr(&format!("\ -[COMPILING] bar v0.0.1 ({url}[/]bar) +[COMPILING] bar v0.0.1 ({url}/bar) [RUNNING] `rustc bar[/]src[/]lib.rs --crate-name bar --crate-type dylib \ -C prefer-dynamic -g \ -C metadata=[..] \ From f47f45946c5a77426e330a9ab5e6403d4dc4af4b Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Sat, 12 Nov 2016 21:49:44 -0800 Subject: [PATCH 06/10] Fix dll prefix/suffix test for windows --- tests/build.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/build.rs b/tests/build.rs index 344b960eba7..3f742a5cfda 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -806,11 +806,13 @@ fn cargo_default_env_metadata_env_var() { --out-dir [..] \ --emit=dep-info,link \ -L dependency={dir}[/]target[/]debug[/]deps \ - --extern bar={dir}[/]target[/]debug[/]deps[/]libbar.dylib` + --extern bar={dir}[/]target[/]debug[/]deps[/]{prefix}bar{suffix}` [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ", dir = p.root().display(), url = p.url(), +prefix = env::consts::DLL_PREFIX, +suffix = env::consts::DLL_SUFFIX, ))); assert_that(p.cargo_process("clean"), execs().with_status(0)); @@ -832,11 +834,13 @@ url = p.url(), --out-dir [..] \ --emit=dep-info,link \ -L dependency={dir}[/]target[/]debug[/]deps \ - --extern bar={dir}[/]target[/]debug[/]deps[/]libbar-[..].dylib` + --extern bar={dir}[/]target[/]debug[/]deps[/]{prefix}bar-[..]{suffix}` [FINISHED] debug [unoptimized + debuginfo] target(s) in [..] ", dir = p.root().display(), url = p.url(), +prefix = env::consts::DLL_PREFIX, +suffix = env::consts::DLL_SUFFIX, ))); } From 3e776404384efd03d6f8e8dfd44494c0ec33e7e9 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Sat, 12 Nov 2016 22:16:56 -0800 Subject: [PATCH 07/10] Fix one more [/] in env-var test for windows --- tests/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/build.rs b/tests/build.rs index 3f742a5cfda..68a3562628c 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -820,7 +820,7 @@ suffix = env::consts::DLL_SUFFIX, // If you set the env-var, then we expect metadata on libbar assert_that(p.cargo_process("build").arg("-v").env("__CARGO_DEFAULT_LIB_METADATA", "1"), execs().with_status(0).with_stderr(&format!("\ -[COMPILING] bar v0.0.1 ({url}[/]bar) +[COMPILING] bar v0.0.1 ({url}/bar) [RUNNING] `rustc bar[/]src[/]lib.rs --crate-name bar --crate-type dylib \ -C prefer-dynamic -g \ -C metadata=[..] \ From 235ebde7d07cceec39bb75c783d7fa66684c8ba2 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Tue, 15 Nov 2016 09:51:12 -0800 Subject: [PATCH 08/10] Ignore the flaky lock test on older windows --- tests/concurrent.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/concurrent.rs b/tests/concurrent.rs index a2b827f565d..bd3963d09aa 100644 --- a/tests/concurrent.rs +++ b/tests/concurrent.rs @@ -343,7 +343,9 @@ fn same_project() { // Make sure that if Cargo dies while holding a lock that it's released and the // next Cargo to come in will take over cleanly. +// older win versions don't support job objects, so skip test there #[test] +#[cfg_attr(target_env = "msvc", ignore)] fn killing_cargo_releases_the_lock() { let p = project("foo") .file("Cargo.toml", r#" @@ -496,4 +498,4 @@ fn no_deadlock_with_git_dependencies() { assert_that(result, execs().with_status(0)) } -} \ No newline at end of file +} From 2af9e1fac580faaf8ae930c2981f4b2aa2740b99 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Tue, 15 Nov 2016 22:48:21 -0800 Subject: [PATCH 09/10] Ignore killing_cargo_releases_the_lock on windows --- tests/concurrent.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/concurrent.rs b/tests/concurrent.rs index bd3963d09aa..ba2300afa25 100644 --- a/tests/concurrent.rs +++ b/tests/concurrent.rs @@ -345,7 +345,7 @@ fn same_project() { // next Cargo to come in will take over cleanly. // older win versions don't support job objects, so skip test there #[test] -#[cfg_attr(target_env = "msvc", ignore)] +#[cfg_attr(target_env = "windows", ignore)] fn killing_cargo_releases_the_lock() { let p = project("foo") .file("Cargo.toml", r#" From 8e22eca9c8f013aad4ca95b7870243b4eb8ac8c6 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Tue, 15 Nov 2016 23:46:57 -0800 Subject: [PATCH 10/10] Target_env -> Target_os --- tests/concurrent.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/concurrent.rs b/tests/concurrent.rs index ba2300afa25..a6eff1e7079 100644 --- a/tests/concurrent.rs +++ b/tests/concurrent.rs @@ -345,7 +345,7 @@ fn same_project() { // next Cargo to come in will take over cleanly. // older win versions don't support job objects, so skip test there #[test] -#[cfg_attr(target_env = "windows", ignore)] +#[cfg_attr(target_os = "windows", ignore)] fn killing_cargo_releases_the_lock() { let p = project("foo") .file("Cargo.toml", r#"