lionkor
lionkor

Reputation: 799

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!

Upvotes: 12

Views: 5748

Answers (3)

user2394284
user2394284

Reputation: 6028

Another cause is that if Ninja itself doesn't see a terminal, such as when you pipe it into Less, it removes color codes from its buffered subprocess output. The way Ninja supports disabling this is with an environment variable:

env CLICOLOR_FORCE=1 ninja | less -r

This also happens if you have Ninja running under Ninja. Which is normally a thing not to do, except: As a quirk of CMake, it is impossible to make the test target depend on unittests being up to date (like you would expect if you come from Meson), so the workaround is to invoke Ninja from a Ctest hook. Which is run by ninja test. Boom, you are running Ninja under Ninja, so that hook actually needs a cmake -E env CLICOLOR_FORCE=1 prefix.

To summarize:

  • Gcc: -fdiagnostics-color=always
  • Clang: -fcolor-diagnostics
    • Windows: -fansi-escape-codes
  • Ninja: env CLICOLOR_FORCE=1 ninja …

Upvotes: 1

befzz
befzz

Reputation: 1292

Windows 10 added support for ANSI escape codes.

-fansi-escape-codes
-fcolor-diagnostics

LLVM(Clang) on windows supports them since:

since

-fansi-escape-codes

Controls whether ANSI escape codes are used instead of 
the Windows Console API to output colored diagnostics.
This option is only used on Windows and defaults to off.

https://clang.llvm.org/docs/UsersManual.html#cmdoption-fansi-escape-codes


Ninja should handle it:

ninja test


EDIT:

Testing:

  1. Create build.ninja file :
rule linkit
  command = clang -fansi-escape-codes -fcolor-diagnostics -
build test: linkit
  1. Type ninja in cmd/powershell

  2. Result:

test result

clang 17.0.1 / Windows 10.0.19045 / ninja 1.11.1 / cmd/powershell

Upvotes: 2

lionkor
lionkor

Reputation: 799

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.

Upvotes: 17

Related Questions