From 9f6d798961b4e2a8adccb88b3ade58ff24fe444a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 23 Nov 2016 08:29:36 -0800 Subject: [PATCH] Emit more info on --message-format=json This adds more output on Cargo's behalf to the output of `--message-format=json`. Cargo will now emit a message when a crate is finished compiling with a list of all files that were just generated along with a message when a build script finishes executing with linked libraries and linked library paths. Closes #3212 --- src/cargo/core/manifest.rs | 21 ++++++- src/cargo/ops/cargo_compile.rs | 4 +- src/cargo/ops/cargo_rustc/custom_build.rs | 15 +++++ src/cargo/ops/cargo_rustc/mod.rs | 37 +++++++++--- src/cargo/util/machine_message.rs | 74 ++++++++++++++++------- tests/build.rs | 28 +++++++++ 6 files changed, 144 insertions(+), 35 deletions(-) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 93fac21fdf9..da40c6a55a0 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -123,7 +123,7 @@ impl Encodable for TargetKind { } } -#[derive(RustcEncodable, RustcDecodable, Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Profile { pub opt_level: String, pub lto: bool, @@ -139,6 +139,25 @@ pub struct Profile { pub panic: Option, } +#[derive(RustcEncodable)] +struct SerializedProfile<'a> { + opt_level: &'a str, + debuginfo: bool, + debug_assertions: bool, + test: bool, +} + +impl Encodable for Profile { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + SerializedProfile { + opt_level: &self.opt_level, + debuginfo: self.debuginfo, + debug_assertions: self.debug_assertions, + test: self.test, + }.encode(s) + } +} + #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct Profiles { pub release: Profile, diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 74b78769476..e2f62e2593b 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -251,7 +251,7 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>, let mut build_config = scrape_build_config(config, jobs, target)?; build_config.release = release; build_config.test = mode == CompileMode::Test || mode == CompileMode::Bench; - build_config.json_errors = message_format == MessageFormat::Json; + build_config.json_messages = message_format == MessageFormat::Json; if let CompileMode::Doc { deps } = mode { build_config.doc_all = deps; } @@ -512,7 +512,7 @@ fn scrape_target_config(config: &Config, triple: &str) let (flags, definition) = value.string(&k)?; let whence = format!("in `{}` (in {})", key, definition.display()); - let (paths, links) = + let (paths, links) = BuildOutput::parse_rustc_flags(&flags, &whence) ?; output.library_paths.extend(paths); diff --git a/src/cargo/ops/cargo_rustc/custom_build.rs b/src/cargo/ops/cargo_rustc/custom_build.rs index eb62f38c522..e412b846ed9 100644 --- a/src/cargo/ops/cargo_rustc/custom_build.rs +++ b/src/cargo/ops/cargo_rustc/custom_build.rs @@ -7,6 +7,7 @@ use std::sync::{Mutex, Arc}; use core::PackageId; use util::{CargoResult, Human, Freshness, Cfg}; use util::{internal, ChainError, profile, paths}; +use util::machine_message; use super::job::Work; use super::{fingerprint, Kind, Context, Unit}; @@ -168,6 +169,7 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) output_file.clone()); let build_scripts = super::load_build_deps(cx, unit); let kind = unit.kind; + let json_messages = cx.build_config.json_messages; // Check to see if the build script as already run, and if it has keep // track of whether it has told us about some explicit dependencies @@ -242,6 +244,19 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) // state informing what variables were discovered via our script as // well. let parsed_output = BuildOutput::parse(&output.stdout, &pkg_name)?; + + if json_messages { + let library_paths = parsed_output.library_paths.iter().map(|l| { + l.display().to_string() + }).collect::>(); + machine_message::emit(machine_message::BuildScript { + package_id: &id, + linked_libs: &parsed_output.library_links, + linked_paths: &library_paths, + cfgs: &parsed_output.cfgs, + }); + } + build_state.insert(id, kind, parsed_output); Ok(()) }); diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index e54f539f392..186ce0d728c 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -42,7 +42,7 @@ pub struct BuildConfig { pub release: bool, pub test: bool, pub doc_all: bool, - pub json_errors: bool, + pub json_messages: bool, } #[derive(Clone, Default)] @@ -246,9 +246,15 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { let cwd = cx.config.cwd().to_path_buf(); rustc.args(&cx.rustflags_args(unit)?); - let json_errors = cx.build_config.json_errors; + let json_messages = cx.build_config.json_messages; let package_id = unit.pkg.package_id().clone(); let target = unit.target.clone(); + let profile = unit.profile.clone(); + let features = cx.resolve.features(unit.pkg.package_id()) + .into_iter() + .flat_map(|i| i) + .map(|s| s.to_string()) + .collect::>(); return Ok(Work::new(move |state| { // Only at runtime have we discovered what the extra -L and -l // arguments are for native libraries, so we process those here. We @@ -273,7 +279,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { } state.running(&rustc); - if json_errors { + if json_messages { rustc.exec_with_streaming( &mut |line| if !line.is_empty() { Err(internal(&format!("compiler stdout is not empty: `{}`", line))) @@ -285,12 +291,11 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { internal(&format!("compiler produced invalid json: `{}`", line)) })?; - machine_message::FromCompiler::new( - &package_id, - &target, - compiler_message - ).emit(); - + machine_message::emit(machine_message::FromCompiler { + package_id: &package_id, + target: &target, + message: compiler_message, + }); Ok(()) }, ).map(|_| ()) @@ -321,6 +326,18 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { fingerprint::append_current_dir(&dep_info_loc, &cwd)?; } + if json_messages { + machine_message::emit(machine_message::Artifact { + package_id: &package_id, + target: &target, + profile: &profile, + features: features, + filenames: filenames.iter().map(|&(ref src, _, _)| { + src.display().to_string() + }).collect(), + }); + } + Ok(()) })); @@ -527,7 +544,7 @@ fn build_base_args(cx: &mut Context, cmd.arg("--color").arg(&color_config.to_string()); } - if cx.build_config.json_errors { + if cx.build_config.json_messages { cmd.arg("--error-format").arg("json"); } diff --git a/src/cargo/util/machine_message.rs b/src/cargo/util/machine_message.rs index 7de1ead0e67..64e6c35f160 100644 --- a/src/cargo/util/machine_message.rs +++ b/src/cargo/util/machine_message.rs @@ -1,30 +1,60 @@ -use rustc_serialize::json; -use core::{PackageId, Target}; +use rustc_serialize::Encodable; +use rustc_serialize::json::{self, Json}; + +use core::{PackageId, Target, Profile}; + +pub trait Message: Encodable { + fn reason(&self) -> &str; +} + +pub fn emit(t: T) { + let json = json::encode(&t).unwrap(); + let mut map = match json.parse().unwrap() { + Json::Object(obj) => obj, + _ => panic!("not a json object"), + }; + map.insert("reason".to_string(), Json::String(t.reason().to_string())); + println!("{}", Json::Object(map)); +} #[derive(RustcEncodable)] pub struct FromCompiler<'a> { - reason: &'static str, - package_id: &'a PackageId, - target: &'a Target, - message: json::Json, -} - -impl<'a> FromCompiler<'a> { - pub fn new(package_id: &'a PackageId, - target: &'a Target, - message: json::Json) - -> FromCompiler<'a> { - FromCompiler { - reason: "compiler-message", - package_id: package_id, - target: target, - message: message, - } + pub package_id: &'a PackageId, + pub target: &'a Target, + pub message: json::Json, +} + +impl<'a> Message for FromCompiler<'a> { + fn reason(&self) -> &str { + "compiler-message" } +} - pub fn emit(self) { - let json = json::encode(&self).unwrap(); - println!("{}", json); +#[derive(RustcEncodable)] +pub struct Artifact<'a> { + pub package_id: &'a PackageId, + pub target: &'a Target, + pub profile: &'a Profile, + pub features: Vec, + pub filenames: Vec, +} + +impl<'a> Message for Artifact<'a> { + fn reason(&self) -> &str { + "compiler-artifact" } } +#[derive(RustcEncodable)] +pub struct BuildScript<'a> { + pub package_id: &'a PackageId, + pub linked_libs: &'a [String], + pub linked_paths: &'a [String], + pub cfgs: &'a [String], +} + +impl<'a> Message for BuildScript<'a> { + fn reason(&self) -> &str { + "build-script-executed" + } +} diff --git a/tests/build.rs b/tests/build.rs index 02e14d18dd3..e6ae434c5e7 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -2411,6 +2411,20 @@ fn compiler_json_error_format() { } } + { + "reason":"compiler-artifact", + "profile": { + "debug_assertions": true, + "debuginfo": true, + "opt_level": "0", + "test": false + }, + "features": [], + "package_id":"bar 0.5.0 ([..])", + "target":{"kind":["lib"],"name":"bar","src_path":"[..]lib.rs"}, + "filenames":["[..].rlib"] + } + { "reason":"compiler-message", "package_id":"foo 0.5.0 ([..])", @@ -2426,6 +2440,20 @@ fn compiler_json_error_format() { }] } } + + { + "reason":"compiler-artifact", + "package_id":"foo 0.5.0 ([..])", + "target":{"kind":["bin"],"name":"foo","src_path":"[..]main.rs"}, + "profile": { + "debug_assertions": true, + "debuginfo": true, + "opt_level": "0", + "test": false + }, + "features": [], + "filenames": ["[..]"] + } "#)); }