diff --git a/src/cargo/core/compiler/context/compilation_files.rs b/src/cargo/core/compiler/context/compilation_files.rs index 276e053cf5e..cb13d669061 100644 --- a/src/cargo/core/compiler/context/compilation_files.rs +++ b/src/cargo/core/compiler/context/compilation_files.rs @@ -49,6 +49,16 @@ pub struct OutputFile { pub flavor: FileFlavor, } +impl OutputFile { + /// Gets the hardlink if present. Otherwise returns the path. + pub fn bindst(&self) -> &PathBuf { + return match self.hardlink { + Some(ref link_dst) => link_dst, + None => &self.path, + }; + } +} + impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> { pub(super) fn new( roots: &[Unit<'a>], diff --git a/src/cargo/core/compiler/context/mod.rs b/src/cargo/core/compiler/context/mod.rs index 8252af66f6b..40eb985c16f 100644 --- a/src/cargo/core/compiler/context/mod.rs +++ b/src/cargo/core/compiler/context/mod.rs @@ -163,10 +163,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { continue; } - let bindst = match output.hardlink { - Some(ref link_dst) => link_dst, - None => &output.path, - }; + let bindst = output.bindst(); if unit.mode == CompileMode::Test { self.compilation.tests.push(( @@ -274,6 +271,23 @@ impl<'a, 'cfg> Context<'a, 'cfg> { Ok(self.compilation) } + /// Returns the executable for the specified unit (if any). + pub fn get_executable(&mut self, unit: &Unit<'a>) -> CargoResult> { + for output in self.outputs(unit)?.iter() { + if output.flavor == FileFlavor::DebugInfo { + continue; + } + + let is_binary = unit.target.is_bin() || unit.target.is_bin_example(); + let is_test = unit.mode.is_any_test() && !unit.mode.is_check(); + + if is_binary || is_test { + return Ok(Option::Some(output.bindst().clone())); + } + } + return Ok(None); + } + pub fn prepare_units( &mut self, export_dir: Option, diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index d1f92ceb89a..95497adbc76 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -409,6 +409,7 @@ fn link_targets<'a, 'cfg>( .map(|s| s.to_owned()) .collect(); let json_messages = bcx.build_config.json_messages(); + let executable = cx.get_executable(unit)?; let mut target = unit.target.clone(); if let TargetSourcePath::Metabuild = target.src_path() { // Give it something to serialize. @@ -432,11 +433,11 @@ fn link_targets<'a, 'cfg>( let dst = match output.hardlink.as_ref() { Some(dst) => dst, None => { - destinations.push(src.display().to_string()); + destinations.push(src.clone()); continue; } }; - destinations.push(dst.display().to_string()); + destinations.push(dst.clone()); hardlink_or_copy(src, dst)?; if let Some(ref path) = output.export_path { let export_dir = export_dir.as_ref().unwrap(); @@ -463,6 +464,7 @@ fn link_targets<'a, 'cfg>( profile: art_profile, features, filenames: destinations, + executable, fresh, }); } diff --git a/src/cargo/util/machine_message.rs b/src/cargo/util/machine_message.rs index 993c00521fa..a41ce918fc8 100644 --- a/src/cargo/util/machine_message.rs +++ b/src/cargo/util/machine_message.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use serde::ser; use serde_json::{self, value::RawValue}; @@ -33,7 +35,8 @@ pub struct Artifact<'a> { pub target: &'a Target, pub profile: ArtifactProfile, pub features: Vec, - pub filenames: Vec, + pub filenames: Vec, + pub executable: Option, pub fresh: bool, } diff --git a/tests/testsuite/bench.rs b/tests/testsuite/bench.rs index 5e57278b48c..c912981678f 100644 --- a/tests/testsuite/bench.rs +++ b/tests/testsuite/bench.rs @@ -1485,3 +1485,46 @@ fn bench_virtual_manifest_all_implied() { .with_stdout_contains("test bench_bar ... bench: [..]") .run(); } + +#[test] +fn json_artifact_includes_executable_for_benchmark() { + if !is_nightly() { + return; + } + + let p = project() + .file( + "benches/benchmark.rs", + r#" + #![feature(test)] + extern crate test; + + use test::Bencher; + + #[bench] + fn bench_foo(_: &mut Bencher) -> () { () } + "#, + ) + .build(); + + p.cargo("bench --no-run --message-format=json") + .with_json(r#" + { + "executable": "[..]/foo/target/release/benchmark-[..][EXE]", + "features": [], + "filenames": [ "[..]/foo/target/release/benchmark-[..][EXE]" ], + "fresh": false, + "package_id": "foo 0.0.1 ([..])", + "profile": "{...}", + "reason": "compiler-artifact", + "target": { + "crate_types": [ "bin" ], + "kind": [ "bench" ], + "edition": "2015", + "name": "benchmark", + "src_path": "[..]/foo/benches/benchmark.rs" + } + } + "#) + .run(); +} diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 09f044f7981..3bf70548d99 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -3083,6 +3083,7 @@ fn compiler_json_error_format() { "overflow_checks": true, "test": false }, + "executable": null, "features": [], "filenames": "{...}", "fresh": false @@ -3110,6 +3111,7 @@ fn compiler_json_error_format() { "overflow_checks": true, "test": false }, + "executable": null, "features": [], "package_id":"bar 0.5.0 ([..])", "target":{ @@ -3162,6 +3164,7 @@ fn compiler_json_error_format() { "overflow_checks": true, "test": false }, + "executable": "[..]/foo/target/debug/foo[EXE]", "features": [], "filenames": "{...}", "fresh": false @@ -3191,6 +3194,7 @@ fn compiler_json_error_format() { "overflow_checks": true, "test": false }, + "executable": null, "features": [], "filenames": "{...}", "fresh": true @@ -3205,6 +3209,7 @@ fn compiler_json_error_format() { "overflow_checks": true, "test": false }, + "executable": null, "features": [], "package_id":"bar 0.5.0 ([..])", "target":{ @@ -3244,6 +3249,7 @@ fn compiler_json_error_format() { "overflow_checks": true, "test": false }, + "executable": "[..]/foo/target/debug/foo[EXE]", "features": [], "filenames": "{...}", "fresh": true @@ -3309,6 +3315,7 @@ fn message_format_json_forward_stderr() { "overflow_checks": false, "test":false }, + "executable": "{...}", "features":[], "filenames": "{...}", "fresh": false diff --git a/tests/testsuite/test.rs b/tests/testsuite/test.rs index d3f24e5bf41..a16dfb3b0be 100644 --- a/tests/testsuite/test.rs +++ b/tests/testsuite/test.rs @@ -3004,6 +3004,7 @@ fn json_artifact_includes_test_flag() { "overflow_checks": true, "test": false }, + "executable": null, "features": [], "package_id":"foo 0.0.1 ([..])", "target":{ @@ -3026,6 +3027,7 @@ fn json_artifact_includes_test_flag() { "overflow_checks": true, "test": true }, + "executable": "[..]/foo-[..]", "features": [], "package_id":"foo 0.0.1 ([..])", "target":{ @@ -3042,6 +3044,63 @@ fn json_artifact_includes_test_flag() { ).run(); } +#[test] +fn json_artifact_includes_executable_for_library_tests() { + let p = project() + .file("src/main.rs", "fn main() { }") + .file("src/lib.rs", r#"#[test] fn lib_test() {}"#) + .build(); + + p.cargo("test --lib -v --no-run --message-format=json") + .with_json(r#" + { + "executable": "[..]/foo/target/debug/foo-[..][EXE]", + "features": [], + "filenames": "{...}", + "fresh": false, + "package_id": "foo 0.0.1 ([..])", + "profile": "{...}", + "reason": "compiler-artifact", + "target": { + "crate_types": [ "lib" ], + "kind": [ "lib" ], + "edition": "2015", + "name": "foo", + "src_path": "[..]/foo/src/lib.rs" + } + } + "#) + .run(); +} + +#[test] +fn json_artifact_includes_executable_for_integration_tests() { + let p = project() + .file("tests/integration_test.rs", r#"#[test] fn integration_test() {}"#) + .build(); + + p.cargo("test -v --no-run --message-format=json --test integration_test") + .with_json(r#" + { + "executable": "[..]/foo/target/debug/integration_test-[..][EXE]", + "features": [], + "filenames": "{...}", + "fresh": false, + "package_id": "foo 0.0.1 ([..])", + "profile": "{...}", + "reason": "compiler-artifact", + "target": { + "crate_types": [ "bin" ], + "kind": [ "test" ], + "edition": "2015", + "name": "integration_test", + "src_path": "[..]/foo/tests/integration_test.rs" + } + } + "#) + .run(); +} + #[test] fn test_build_script_links() { let p = project()