Colored C++ Compiler Output with Ninja (Clang/GCC)

Austin Lasher
3 min readMar 10, 2018

--

At the time of writing, if you Google search something along the lines of “colored compiler output GCC”, there top responses are littered with custom scripts or using gccfilter to do this. While they may get the job done, if the desire is simply to get some ANSI-colored output, an external tool is not required — recent Clang and GCC toolchains support this already. GCC has supported an option for this since GCC 4.9, called -fdiagnostics-color. On Clang, there’s an equivalent option with a frustratingly similar name: -fcolor-diagnostics.

Cool, right? Well, if you’ve read the title of this article, then you probably already know there’s a problem. The output doesn’t automatically add color with Ninja for either compiler. This is a popular “bug” for Clang and GCC on the ninja-build Github first dating all the way back to 2012, but will likely never be fixed (read on, and read the ticket to learn why.) Below I’ve included a simple demonstration of what I mean, for those not familiar.

Make colors the output fine by default, nice.

My default configuration with Make/Clang colors my output just fine. But if I simply change my generator to Ninja, the pretty coloring is unfortunately gone.

Yuck. Ninja defaults don’t work, even with same compiler config as Make.

Same compiler, same default configuration, the only difference above is the replacement of Make with Ninja. Although the above example is using Clang on macOS, the problem is still present on Linux with either Clang or GCC. With GCC, many said simply setting $GCC_COLORS should solve the issue as it will configure -fdiagnostic-color to equal auto, but that also didn’t work on Ninja.

So, what gives? The problem is that, by default, neither Clang or GCC will add ANSI-formatted colors to your output if they detect the output medium is not a terminal. On Ninja, it intercepts this output before it hits the terminal, thus the default configuration doesn’t generate ANSI-colors at all. Instead, you have to explicitly specify to always include ANSI-colored output, even if the output isn’t a terminal. Although you could easily add the appropriate command line argument to enable this all the time, sometimes this ANSI littering prevention is actually desirable — like when piping the compiler output to a file. If you’re sharing code with a team, it’s very likely someone will eventually want to pipe this somewhere, or toss it around for whatever reason.

For our codebase, I decided to add a CMake option where each developer could choose to enable it if he or she wanted. I’ve included my implementation below, which works for GCC or Clang. Since I don’t know how many of my teammates pipe around the compiler output, I decided to set it to be disabled by default (at least for now).

Lookin’ good!

Below I’ve put the CMake implemention we ended up using. I hope this shreds an hour or so of head scratching on your end, be sure to let me know if it did. Enjoy!

option (FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." FALSE)if (${FORCE_COLORED_OUTPUT})
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
add_compile_options (-fdiagnostics-color=always)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options (-fcolor-diagnostics)
endif ()
endif ()

--

--

Austin Lasher

Software @ Bloomberg. Views expressed here are strictly my own.