Skip to content

#![windows_subsystem = "windows"] hides cargo test output #67159

Open

Description

@utoalex

Problem
Calling cargo test on a project that has the #![windows_subsystem = "windows"] global attribute does not show the expected human-readable output.

Instead of showing

> cargo test
   Compiling no_output v0.1.0 (C:\Programming\no_output)
    Finished dev [unoptimized + debuginfo] target(s) in 0.71s
     Running target\debug\deps\no_output-c8b57bda8502ba55.exe

running 1 test
test tests::test_panic ... FAILED

failures:

---- tests::test_panic stdout ----
thread 'tests::test_panic' panicked at 'This tape has just self-destructed!', src\main.rs:9:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.


failures:
    tests::test_panic

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--bin no_output'

it shows

> cargo test
   Compiling no_output v0.1.0 (C:\Programming\no_output)
    Finished dev [unoptimized + debuginfo] target(s) in 1.40s
     Running target\debug\deps\no_output-c8b57bda8502ba55.exe
error: test failed, to rerun pass '--bin no_output'

which not quite as informative as the former message (it does not tell which tests failed).

Steps
This requires a Windows computer.

  1. Create a new project with cargo new.
  2. Copy-paste the following into your main.rs file:
#![windows_subsystem = "windows"]

fn main() {
    println!("Hello, world!");
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_panic() {
        panic!("This tape has just self-destructed!");
    }
}
  1. call cargo test on your project.

Possible Solution(s)
My guess is that this is due to executables targeting the Windows subsystem having no console and standard output initialized by default on Windows. Therefore, 2 possible solutions come to my mind:

  • forcing cargo test-compiled executables to target the console subsystem when compiled for Windows;
  • or having cargo explicitly initialize the console in the test framework automatically included in test executables: AFAIK this can be achieved by calling the AllocConsole() function provided by the Windows API.

Notes

Output of cargo version: this happens on pretty much any cargo version.
Tested on cargo 1.39.0 (1c6ec66d5 2019-09-30) and cargo 1.41.0-nightly (626f0f40e 2019-12-03).

Apologies if this has already been reported. I was unable to find a similar issue in the repository 😅

Activity

  1. transferred this issue fromrust-lang/cargoon Dec 8, 2019
  2. ehuss commented on Dec 8, 2019

    @ehuss
    Contributor

    Thanks for the report. I have moved this to rust-lang/rust, as that is where issues for libtest are tracked. This looks to be an issue with the libtest harness.

    Interestingly, the output works when run from a cygwin/msys shell, but doesn't with cmd or powershell.

    As a workaround, perhaps something like this well help:

    #![cfg_attr(not(test), windows_subsystem = "windows")]
  3. added
    A-libtestArea: `#[test]` / the `test` library
    C-bugCategory: This is a bug.
    O-windows-msvcToolchain: MSVC, Operating system: Windows
    T-libs-api[DEPRECATED; DO NOT USE]
    on Dec 8, 2019
  4. jonas-schievink commented on Dec 8, 2019

    @jonas-schievink
    Contributor

    Isn't this expected behavior?

  5. ehuss commented on Dec 8, 2019

    @ehuss
    Contributor

    Good question, I have no idea! I could see an argument that when built with --test that rustc could ignore the windows_subsystem attribute, since the intent is to write to the console. But I do not know what the consequences would be.

  6. retep998 commented on Dec 9, 2019

    @retep998
    Contributor

    I'm pretty sure this is due to defaults regarding how console and windows processes inherit stdout/stdin differently. By default console processes will inherit stdout/stdin from the parent process while windows processes do not. I believe the reason we allow stdout/stdin to be inherited instead of explicitly piping it is to allow console processes to emit colors using the conhost color API, because otherwise colors would not work in some situations on Windows.

  7. added
    O-windowsOperating system: Windows
    and removed
    O-windows-msvcToolchain: MSVC, Operating system: Windows
    on Dec 9, 2019
  8. Songtronix commented on Jan 29, 2020

    @Songtronix

    This issue isn't limited to tests only. I build a GUI currently and want to avoid popping up a console on start. However using the cli version is not possible anymore because it does not output anything due to stdout/stdin not being attached to anything.
    It would be very helpful if there is a winapi call to make which allows to attach stdout/stdin to the parent. This can be used for cargo test too.

  9. phiresky commented on Dec 7, 2021

    @phiresky

    Here's a workaround to not show a console on start, but still output the normal output when started from powershell or cmd:

    #![windows_subsystem = "windows"]
    fn main() {
        #[cfg(target_os = "windows")]
        {
            use winapi::um::wincon::{AttachConsole, ATTACH_PARENT_PROCESS};
            unsafe {
                AttachConsole(ATTACH_PARENT_PROCESS);
            }
            // ...
        }

    from here: https://www.reddit.com/r/learnrust/comments/jaqfcx/windows_print_to_hidden_console_window/

  10. ChrisDenton commented on Dec 7, 2021

    @ChrisDenton
    Member

    That'll work but be aware that the console will not be waiting for output. This means the prompt may switch back to interactive mode while the program is still running.

    EDIT: Just clarify the "may" there, it should be fine when running from cargo or another console process that will wait for the "windows" process to exit. But if you run it directly from powershell or cmd then it won't wait.

  11. phiresky commented on Dec 7, 2021

    @phiresky

    After testing, i can not recommend the above workaround. Like you said it doesn't make the console wait for the output, leading to weird output intermingling and undesired behaviour when the console is closed (program might get killed with broken pipe or it might not)

  12. MunchyYDL commented on Jan 9, 2022

    @MunchyYDL

    This problem had me on a wild goose chase for a couple of hours yesterday. 🙂

    As a relative newbie to Rust, it was a bit hard to know what to look for when I suddenly couldn't run my newly added tests.

    After some digging around, my solution to this specific problem is to attribute only the main() function instead of setting it as a crate level attribute.

    Maybe this needs to be mentioned somewhere in some docs relating to either cargo test and/or the docs for the attribute, not only here in the problem report?

    Example:

    My example is a bit contrived, as I really don't need to switch the subsystem for this example, but it exists there only to show how you can place the attribute on the main function only, instead of as a crate level attribute.

    #[windows_subsystem = "windows"]  // Just on main, not a crate level attribute (# vs #!)
    fn main() {
        println!("Works fine with cargo test!");
    }
    
    #[cfg(test)]
    mod main_tests {
    
        #[test]
        fn it_works() {
            let result = 2 + 2;
            assert_eq!(result, 4);
        }
    }
  13. ehuss commented on Jan 9, 2022

    @ehuss
    Contributor

    @MunchyYDL #[windows_subsystem] is only valid at the crate root. I have posted #92701 to fix the warning for that.

  14. MunchyYDL commented on Jan 10, 2022

    @MunchyYDL

    Ah, yes, my bad, I tricked myself into thinking it worked, but I only started the program from within VS Code, not as a standalone. DOH!

    Thanks for clearing that up for me! :)

  15. 04041b commented on May 28, 2024

    @04041b

    #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
    Allows console to show up in debug build but not release build.

  16. yangcancai commented on Mar 17, 2025

    @yangcancai

    #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
    Can I use this property in lib crate or only in main crate?

  17. retep998 commented on Mar 17, 2025

    @retep998
    Contributor

    Changing the subsystem is something that should only be done in a binary crate. It makes no sense to set it in a library crate and I'd argue it should emit an error if it doesn't already in that case.

  18. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-libtestArea: `#[test]` / the `test` libraryC-bugCategory: This is a bug.O-windowsOperating system: WindowsT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions