cargo: Cargo doesn’t display output from a command in build.rs

When a command, e.g. Command::new("nasm"), in build.rs returns an error, Cargo doesn’t output the error to standard output. This is especially frustrating when debugging a Makefile that’s run by Command::new("make").

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 20
  • Comments: 25 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Note to anyone who found this issue by googling: you can pass -vv now to cargo to display the output. See commit 2c0d6af1739be737133e2385033d1395fbcd8342 and #1106 for details.

I mentioned this on the new linked issue, but it might be worth mentioning here that you can currently do println!(cargo:warning=MESSAGE) to get output from build scripts. It will always be prefixed with "warning: " however.

So, for quick debugging of a build script you could use this drop in replacement for println:

macro_rules! p {
    ($($tokens: tt)*) => {
        println!("cargo:warning={}", format!($($tokens)*))
    }
}

usage example:

// in build.rs

macro_rules! p {
    ($($tokens: tt)*) => {
        println!("cargo:warning={}", format!($($tokens)*))
    }
}

fn main() {
    let x = 42;
    p!("{x}");
}

This is actually done by default to turn down the noise from builds. If you’re debugging makefiles I’d recommend having the build command itself forcibly fail to ensure that Cargo prints the output of the build script.

You shouldn’t use println! for debug printing a build.rs script; the cargo build system uses the output of that script to record build & rebuild metadata, as documented here: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script

Cargo shouldn’t use println! for transmitting commands.

You can check the full output in target/build/$crate-$hash/output and you can forcibly fail with a panic!() or a std::os::set_exit_status(nonzero_code). I think that printing this out for --verbose would be a bit too verbose, but we could consider printing where the output goes I suppose. In general a successful build script is something you largely want to ignore 90% of the time.

Why would I write a build script with println! if I didn’t want to see any output when building? Hopefully this will get fixed.

Why not display this output when using --verbose? How do I forcibly fail?

I don’t think this issue should be closed. It’s very convenient to use println when debugging. Not being able to use it in part of the codebase is cumbersome and introduces a significant mental burden.

You shouldn’t use println! for debug printing a build.rs script; the cargo build system uses the output of that script to record build & rebuild metadata, as documented here: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script

For those who still doesn’t see any output even after passing -vv:

  1. Slightly modify the build.rs like adding a new line(force cargo to rebuild it) and using cargo build -vv, then you’ll see the outputs.
  2. Using find . -name output, you will be able to get the path(target/build/$crate-$hash/output) to the output file, then you can cat it.

You shouldn’t use println! for debug printing a build.rs script; the cargo build system uses the output of that script to record build & rebuild metadata, as documented here: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script

That link states that any output not starting with cargo: will be ignored. As long as you avoid the cargo: prefix for debugging, that link implies that it’s fine to use println! for debugging.

I’ve managed to debug build.rs scripts by placing a panic! at the end. As it crashes, it will print everything to standard output, including any println! (the universal debugger 😄).

// in build.rs

macro_rules! p {
    ($($tokens: tt)*) => {
        println!("cargo:warning={}", format!($($tokens)*))
    }
}

fn main() {
    let x = 42;
    p!("{x}");
}

Thanks, Really appreciated

At least the output of eprintln! goes through in that case.

Another (terrible) hack, but if you panic! at the very end of your build script, it will at least allow you to see any prints emitted from the script. This can be useful if you just need some quick insight into what is happening in the script.

@gdnathan

I could read that cargo is using the build script output for IPC. But it’s only doing so when there is a cargo: prefix, so why not let pass the rest of it when there is not prefix ???

That answer is in the second post

This is actually done by default to turn down the noise from builds. If you’re debugging makefiles I’d recommend having the build command itself forcibly fail to ensure that Cargo prints the output of the build script.

As other posts in this thread say

  • Check target/build/$crate-$hash/output
  • Pass -vv
  • Fail your build script

@notdanilo , I opened a new issue based on your suggestion with an alternative solution:

Cargo shouldn’t use println! for transmitting commands.

Cargo if it wants to use print, open a special file and print to it instead of stderr/stdout. Then, users do not have to open a file for their print. It is more reasonable for the tool (cargo) to open a file for its commands than the user to open a file for its debug printing.

If anyone likes it, or have a different proposal, please, upvote it or comment on it: https://github.com/rust-lang/cargo/issues/10475

Same issue here. Cargo run does not print. Compiling directly with rustc and running main.exe does print.

There is also -- --nocapture which shows the output when running tests. Maybe it helps but I have not tried.