Search code examples
c++cninja

Ninja Build System + gcc/clang doesn't output diagnostic colors


When invoking ninja on a C or C++ (hence both tags) project, with the clang or gcc compiler, the output is not colored with ANSI colors.

For example:

error should be red, but isn't. warning should be yellow/orange, but isn't.

Everything is the same color, and it's really hard to tell what's going on!


Solution

  • Why this happens

    This happens because ninja internally creates a pipe(), which stdout and stderr from the compiler (gcc or clang in this case) is re-routed. This makes the check inside gcc and clang, which checks for terminals (which may support color), fail.

    A check such as isatty(stdout) does not return true for a pipe, even though that pipe is then forwarded to stdout once again.

    It's documented

    Ninja's FAQ talks about this on GitHub.com, but this FAQ is not included with the software, not mentioned in the --help, there are no ninja manpages, and common search engines (ddg, google) do not seem to find that FAQ for common search queries relating to color.

    Hence, this post, since SO has good SSO.

    The fix

    Add -fdiagnostics-color=always to your C or CXX flags. For example, with cmake, you can append -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always (or CMAKE_C_FLAGS for C) (or, if you are using CMake 3.24 or later, you can use the CMAKE_COLOR_DIAGNOSTICS variable or environment variable).

    This works for gcc (as documented in its manpage) and clang (clang's manpages do not mention this option, but it is included in their command line reference on llvm.org.

    As a permanent fix, you could append the following to your .zshrc, .bashrc, or similar:

    # force C colored diagnostic output
    export CFLAGS="${CFLAGS} -fdiagnostics-color=always"
    # force C++ colored diagnostic output
    export CXXFLAGS="${CXXFLAGS} -fdiagnostics-color=always"
    export CCFLAGS="${CCFLAGS} -fdiagnostics-color=always"
    # force C, C++, Cpp (pre-processor) colored diagnostic output
    export CPPFLAGS="${CPPFLAGS} -fdiagnostics-color=always"
    

    You should only do this if you KNOW you will never need to pipe your compiler's output anywhere else. Also, this will only work with clang and gcc, and other compilers which support this - so make sure you dont use compilers that choke on this flag.