diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 1590517e203..3402b8c458e 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -490,8 +490,8 @@ pub fn compile_main( } if options.print_acir { - println!("Compiled ACIR for main (unoptimized):"); - println!("{}", compiled_program.program); + noirc_errors::println_to_stdout!("Compiled ACIR for main (unoptimized):"); + noirc_errors::println_to_stdout!("{}", compiled_program.program); } Ok((compiled_program, warnings)) diff --git a/compiler/noirc_errors/src/lib.rs b/compiler/noirc_errors/src/lib.rs index 29f4e6213ed..a775bbf2e8b 100644 --- a/compiler/noirc_errors/src/lib.rs +++ b/compiler/noirc_errors/src/lib.rs @@ -7,3 +7,33 @@ mod position; pub mod reporter; pub use position::{Located, Location, Position, Span, Spanned}; pub use reporter::{CustomDiagnostic, DiagnosticKind}; +use std::io::Write; + +/// Print the input to stdout, and exit gracefully if `SIGPIPE` is received. +/// Rust ignores `SIGPIPE` by default, converting pipe errors into `ErrorKind::BrokenPipe` +pub fn print_to_stdout(args: std::fmt::Arguments) { + let mut stdout = std::io::stdout(); + if let Err(e) = stdout.write_fmt(args) { + if e.kind() == std::io::ErrorKind::BrokenPipe { + // Gracefully exit on broken pipe + std::process::exit(0); + } else { + panic!("Unexpected error: {e}"); + } + } +} + +/// Macro to print formatted output to stdout +#[macro_export] +macro_rules! print_to_stdout { + ($($arg:tt)*) => { + noirc_errors::print_to_stdout(format_args!($($arg)*)) + }; +} + +#[macro_export] +macro_rules! println_to_stdout { + ($($arg:tt)*) => { + noirc_errors::print_to_stdout(format_args!("{}\n", format!($($arg)*))) + }; +} diff --git a/compiler/noirc_evaluator/src/ssa/builder.rs b/compiler/noirc_evaluator/src/ssa/builder.rs index 35053f3c3ac..ed562d514c9 100644 --- a/compiler/noirc_evaluator/src/ssa/builder.rs +++ b/compiler/noirc_evaluator/src/ssa/builder.rs @@ -3,6 +3,7 @@ use std::io::Write; use std::path::Path; use std::{collections::HashMap, path::PathBuf}; +use noirc_errors::println_to_stdout; use noirc_frontend::monomorphization::ast::Program; use crate::errors::RuntimeError; @@ -201,7 +202,7 @@ impl<'local> SsaBuilder<'local> { }; if print_ssa_pass { - println!("After {msg}:\n{}", self.ssa.print_with(self.files)); + println_to_stdout!("After {msg}:\n{}", self.ssa.print_with(self.files)); } self } @@ -214,7 +215,7 @@ pub(super) fn time(name: &str, print_timings: bool, f: impl FnOnce() -> T) -> if print_timings { let end_time = chrono::Utc::now().time(); - println!("{name}: {} ms", (end_time - start_time).num_milliseconds()); + println_to_stdout!("{name}: {} ms", (end_time - start_time).num_milliseconds()); } result diff --git a/tooling/artifact_cli/src/execution.rs b/tooling/artifact_cli/src/execution.rs index 47a0f771f29..69ea6f3837a 100644 --- a/tooling/artifact_cli/src/execution.rs +++ b/tooling/artifact_cli/src/execution.rs @@ -84,13 +84,13 @@ pub fn save_and_check_witness( witness_dir: Option<&Path>, witness_name: Option<&str>, ) -> Result<(), CliError> { - println!("[{circuit_name}] Circuit witness successfully solved"); + noirc_errors::println_to_stdout!("[{circuit_name}] Circuit witness successfully solved"); // Save first, so that we can potentially look at the output if the expectations fail. if let Some(witness_dir) = witness_dir { save_witness(&results.witness_stack, circuit_name, witness_dir, witness_name)?; } if let Some(ref return_value) = results.return_values.actual_return { - println!("[{circuit_name}] Circuit output: {return_value:?}"); + noirc_errors::println_to_stdout!("[{circuit_name}] Circuit output: {return_value:?}"); } check_witness(circuit, results.return_values) } @@ -112,7 +112,11 @@ pub fn save_witness( } } - println!("[{}] Witness saved to {}", circuit_name, witness_path.display()); + noirc_errors::println_to_stdout!( + "[{}] Witness saved to {}", + circuit_name, + witness_path.display() + ); Ok(()) }