diff --git a/src/cargo/ops/cargo_rustc/output_depinfo.rs b/src/cargo/ops/cargo_rustc/output_depinfo.rs index 188956187a8..c559e4741ee 100644 --- a/src/cargo/ops/cargo_rustc/output_depinfo.rs +++ b/src/cargo/ops/cargo_rustc/output_depinfo.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use std::io::{Write, BufWriter}; -use std::fs::File; +use std::io::{Write, BufWriter, ErrorKind}; +use std::fs::{self, File}; use std::path::{Path, PathBuf}; use ops::{Context, Unit}; @@ -22,10 +22,9 @@ fn render_filename>(path: P, basedir: Option<&str>) -> CargoResul fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet, context: &mut Context<'a, 'b>, unit: &Unit<'a>, visited: &mut HashSet>) -> CargoResult<()> { - if visited.contains(unit) { + if !visited.insert(unit.clone()) { return Ok(()); } - visited.insert(unit.clone()); // Add dependencies from rustc dep-info output (stored in fingerprint directory) let dep_info_loc = fingerprint::dep_info_loc(context, unit); @@ -33,6 +32,10 @@ fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet, context: &mut Context< for path in paths { deps.insert(path); } + } else { + debug!("can't find dep_info for {:?} {:?}", + unit.pkg.package_id(), unit.profile); + return Err(internal("dep_info missing")); } // Add rerun-if-changed dependencies @@ -56,18 +59,32 @@ fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet, context: &mut Context< pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) -> CargoResult<()> { let mut deps = HashSet::new(); let mut visited = HashSet::new(); - add_deps_for_unit(&mut deps, context, unit, &mut visited)?; + let success = add_deps_for_unit(&mut deps, context, unit, &mut visited).is_ok(); let basedir = None; // TODO for (_filename, link_dst, _linkable) in context.target_filenames(unit)? { if let Some(link_dst) = link_dst { let output_path = link_dst.with_extension("d"); - let target_fn = render_filename(link_dst, basedir)?; - let mut outfile = BufWriter::new(File::create(output_path)?); - write!(outfile, "{}:", target_fn)?; - for dep in &deps { - write!(outfile, " {}", render_filename(dep, basedir)?)?; + if success { + let mut outfile = BufWriter::new(File::create(output_path)?); + let target_fn = render_filename(link_dst, basedir)?; + write!(outfile, "{}:", target_fn)?; + for dep in &deps { + write!(outfile, " {}", render_filename(dep, basedir)?)?; + } + writeln!(outfile, "")?; + } else { + // dep-info generation failed, so delete output file. This will usually + // cause the build system to always rerun the build rule, which is correct + // if inefficient. + match fs::remove_file(output_path) { + Err(err) => { + if err.kind() != ErrorKind::NotFound { + return Err(err.into()); + } + } + _ => () + } } - writeln!(outfile, "")?; } } Ok(()) diff --git a/tests/dep-info.rs b/tests/dep-info.rs new file mode 100644 index 00000000000..2f0513e7b7e --- /dev/null +++ b/tests/dep-info.rs @@ -0,0 +1,79 @@ +extern crate cargotest; +extern crate hamcrest; + +use cargotest::support::{basic_bin_manifest, main_file, execs, project}; +use hamcrest::{assert_that, existing_file}; + +#[test] +fn build_dep_info() { + let p = project("foo") + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])); + + assert_that(p.cargo_process("build"), execs().with_status(0)); + + let depinfo_bin_path = &p.bin("foo").with_extension("d"); + + assert_that(depinfo_bin_path, existing_file()); +} + +#[test] +fn build_dep_info_lib() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["lib"] + "#) + .file("src/lib.rs", "") + .file("examples/ex.rs", ""); + + assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0)); + assert_that(&p.example_lib("ex", "lib").with_extension("d"), existing_file()); +} + + +#[test] +fn build_dep_info_rlib() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["rlib"] + "#) + .file("src/lib.rs", "") + .file("examples/ex.rs", ""); + + assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0)); + assert_that(&p.example_lib("ex", "rlib").with_extension("d"), existing_file()); +} + +#[test] +fn build_dep_info_dylib() { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [[example]] + name = "ex" + crate-type = ["dylib"] + "#) + .file("src/lib.rs", "") + .file("examples/ex.rs", ""); + + assert_that(p.cargo_process("build").arg("--example=ex"), execs().with_status(0)); + assert_that(&p.example_lib("ex", "dylib").with_extension("d"), existing_file()); +}