diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 3e58b1a6a2f..620ff267f2e 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -230,11 +230,9 @@ fn compile<'a, 'cfg: 'a>(cx: &mut Context<'a, 'cfg>, } else { rustc(cx, unit, exec.clone())? }; - let link_work1 = link_targets(cx, unit)?; - let link_work2 = 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); + let dirty = work.then(link_targets(cx, unit, false)?).then(dirty); + let fresh = link_targets(cx, unit, true)?.then(fresh); (dirty, fresh, freshness) }; jobs.enqueue(cx, unit, Job::new(dirty, fresh), freshness)?; @@ -291,10 +289,6 @@ fn rustc(cx: &mut Context, unit: &Unit, exec: Arc) -> CargoResult) -> CargoResult) -> CargoResult CargoResult { +fn link_targets(cx: &mut Context, unit: &Unit, fresh: bool) -> CargoResult { let filenames = cx.target_filenames(unit)?; + let package_id = unit.pkg.package_id().clone(); + let target = unit.target.clone(); + let profile = unit.profile.clone(); + let features = cx.resolve.features_sorted(&package_id).into_iter() + .map(|s| s.to_owned()) + .collect(); + let json_messages = cx.build_config.json_messages; + 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 { + let mut destinations = vec![]; + for &(ref src, ref link_dst, _linkable) in filenames.iter() { // 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() { + if !src.exists() { continue } - let dst = link_dst.unwrap(); + let dst = match link_dst.as_ref() { + Some(dst) => dst, + None => { + destinations.push(src.display().to_string()); + continue; + } + }; + destinations.push(dst.display().to_string()); debug!("linking {} to {}", src.display(), dst.display()); if dst.exists() { @@ -457,16 +454,27 @@ fn link_targets(cx: &mut Context, unit: &Unit) -> CargoResult { human(format!("failed to remove: {}", dst.display())) })?; } - fs::hard_link(&src, &dst) + fs::hard_link(src, dst) .or_else(|err| { debug!("hard link failed {}. falling back to fs::copy", err); - fs::copy(&src, &dst).map(|_| ()) + fs::copy(src, dst).map(|_| ()) }) .chain_error(|| { human(format!("failed to link or copy `{}` to `{}`", src.display(), dst.display())) })?; } + + if json_messages { + machine_message::emit(machine_message::Artifact { + package_id: &package_id, + target: &target, + profile: &profile, + features: features, + filenames: destinations, + fresh: fresh, + }); + } Ok(()) })) } diff --git a/src/cargo/util/machine_message.rs b/src/cargo/util/machine_message.rs index 9626494cd3d..1d4f33a86da 100644 --- a/src/cargo/util/machine_message.rs +++ b/src/cargo/util/machine_message.rs @@ -33,6 +33,7 @@ pub struct Artifact<'a> { pub profile: &'a Profile, pub features: Vec, pub filenames: Vec, + pub fresh: bool, } impl<'a> Message for Artifact<'a> { diff --git a/tests/build.rs b/tests/build.rs index c937f0487e4..433e2ed51e0 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -2512,8 +2512,9 @@ fn compiler_json_error_format() { authors = ["wycats@example.com"] "#) .file("bar/src/lib.rs", r#"fn dead() {}"#); + p.build(); - assert_that(p.cargo_process("build").arg("-v") + assert_that(p.cargo("build").arg("-v") .arg("--message-format").arg("json"), execs().with_status(0).with_json(r#" { @@ -2544,7 +2545,8 @@ fn compiler_json_error_format() { "name":"bar", "src_path":"[..]lib.rs" }, - "filenames":["[..].rlib"] + "filenames":["[..].rlib"], + "fresh": false } { @@ -2575,7 +2577,54 @@ fn compiler_json_error_format() { "test": false }, "features": [], - "filenames": ["[..]"] + "filenames": ["[..]"], + "fresh": false + } +"#)); + + // With fresh build, we should repeat the artifacts, + // but omit compiler warnings. + assert_that(p.cargo("build").arg("-v") + .arg("--message-format").arg("json"), + execs().with_status(0).with_json(r#" + { + "reason":"compiler-artifact", + "profile": { + "debug_assertions": true, + "debuginfo": 2, + "opt_level": "0", + "test": false + }, + "features": [], + "package_id":"bar 0.5.0 ([..])", + "target":{ + "kind":["lib"], + "crate_types":["lib"], + "name":"bar", + "src_path":"[..]lib.rs" + }, + "filenames":["[..].rlib"], + "fresh": true + } + + { + "reason":"compiler-artifact", + "package_id":"foo 0.5.0 ([..])", + "target":{ + "kind":["bin"], + "crate_types":["bin"], + "name":"foo", + "src_path":"[..]main.rs" + }, + "profile": { + "debug_assertions": true, + "debuginfo": 2, + "opt_level": "0", + "test": false + }, + "features": [], + "filenames": ["[..]"], + "fresh": true } "#)); } @@ -2633,7 +2682,8 @@ fn message_format_json_forward_stderr() { "test":false }, "features":[], - "filenames":["[..]"] + "filenames":[], + "fresh": false } "#)); }