diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 6c59910537c..24f9deb0a80 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::{OsStr, OsString}; use std::fs; +use std::io::{self, Write}; use std::path::{self, PathBuf}; use std::sync::Arc; @@ -297,15 +298,22 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { Ok(()) }, &mut |line| { - let compiler_message = json::Json::from_str(line).map_err(|_| { - internal(&format!("compiler produced invalid json: `{}`", line)) - })?; - - machine_message::emit(machine_message::FromCompiler { - package_id: &package_id, - target: &target, - message: compiler_message, - }); + // stderr from rustc can have a mix of JSON and non-JSON output + if line.starts_with("{") { + // Handle JSON lines + let compiler_message = json::Json::from_str(line).map_err(|_| { + internal(&format!("compiler produced invalid json: `{}`", line)) + })?; + + machine_message::emit(machine_message::FromCompiler { + package_id: &package_id, + target: &target, + message: compiler_message, + }); + } else { + // Forward non-JSON to stderr + writeln!(io::stderr(), "{}", line)?; + } Ok(()) }, ).map(|_| ()) diff --git a/tests/build.rs b/tests/build.rs index e6ae434c5e7..7b19633b994 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -2470,6 +2470,55 @@ fn wrong_message_format_option() { r#"[ERROR] Could not match 'xml' with any of the allowed variants: ["Human", "Json"]"#)); } +#[test] +fn message_format_json_forward_stderr() { + if is_nightly() { return } + + let p = project("foo") + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/main.rs", "fn main() { let unused = 0; }"); + + assert_that(p.cargo_process("rustc").arg("--bin").arg("foo") + .arg("--message-format").arg("JSON").arg("--").arg("-Zno-trans"), + execs() + .with_stderr_contains("[WARNING] the option `Z` is unstable [..]") + .with_json(r#" + { + "reason":"compiler-message", + "package_id":"foo 0.5.0 ([..])", + "target":{"kind":["bin"],"name":"foo","src_path":"[..]"}, + "message":{ + "children":[],"code":null,"level":"warning","rendered":null, + "message":"unused variable: `unused`, #[warn(unused_variables)] on by default", + "spans":[{ + "byte_end":22,"byte_start":16,"column_end":23,"column_start":17,"expansion":null, + "file_name":"[..]","is_primary":true,"label":null,"line_end":1,"line_start":1, + "suggested_replacement":null, + "text":[{ + "highlight_end":23, + "highlight_start":17, + "text":"fn main() { let unused = 0; }" + }] + }] + } + } + + { + "reason":"compiler-artifact", + "package_id":"foo 0.5.0 ([..])", + "target":{"kind":["bin"],"name":"foo","src_path":"[..]"}, + "profile":{ + "debug_assertions":true, + "debuginfo":true, + "opt_level":"0", + "test":false + }, + "features":[], + "filenames":["[..]"] + } +"#)); +} + #[test] fn no_warn_about_package_metadata() { let p = project("foo")