From f0b7196db8c4dd34c4b2247943e4dac44864b89c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 29 Aug 2023 02:13:00 +0200 Subject: Add diagnostics color support on Windows (GH issue #312) Note that currently this has to be enabled with an explicit --diag-color option. In the future the plan is to enable it by default if supported. --- libbuild2/cc/common.cxx | 47 +++++++++++++++++++++++++++++++++++++++-------- libbuild2/diagnostics.cxx | 40 +++++++++++++++++++++++++--------------- libbuild2/utility.hxx | 6 ++---- 3 files changed, 66 insertions(+), 27 deletions(-) diff --git a/libbuild2/cc/common.cxx b/libbuild2/cc/common.cxx index 07a4d48..2f428c3 100644 --- a/libbuild2/cc/common.cxx +++ b/libbuild2/cc/common.cxx @@ -1618,9 +1618,35 @@ namespace build2 { case compiler_class::msvc: { - // Note: see init_diag logic if enabling anything here (probably - // need an "override disable" mode or some such). + // MSVC has the /diagnostics: option which has an undocumented value + // `color`. It's unclear from which version of MSVC this value is + // supported, but it works in 17.0, so let's start from there. // + // Note that there is currently no way to disable color in the MSVC + // diagnostics specifically (the /diagnostics:* option values are + // cumulative and there doesn't seem to be a `color-` value). This + // is probably not a big deal since one can just disable the color + // globally (--no-diag-color). + // + // Note that clang-cl appears to use -fansi-escape-codes. See GH + // issue #312 for background. + // + if (show_diag_color ()) + { + if (cvariant.empty () && + (cmaj > 19 || (cmaj == 19 && cmin >= 30))) + { + // Check for the prefix in case /diagnostics:color- gets added + // eventually. + // + if (!find_option_prefixes ({"/diagnostics:color", + "-diagnostics:color"}, args)) + { + args.push_back ("/diagnostics:color"); + } + } + } + break; } case compiler_class::gcc: @@ -1628,13 +1654,18 @@ namespace build2 // Enable/disable diagnostics color unless a custom option is // specified. // - // Supported from GCC 4.9 and (at least) from Clang 3.5. Clang - // supports -f[no]color-diagnostics in addition to the GCC's - // spelling. + // Supported from GCC 4.9 (8.1 on Windows) and (at least) from Clang + // 3.5. Clang supports -f[no]color-diagnostics in addition to the + // GCC's spelling. // - if (ctype == compiler_type::gcc ? cmaj > 4 || (cmaj == 4 && cmin >= 9) : - ctype == compiler_type::clang ? cmaj > 3 || (cmaj == 3 && cmin >= 5) : - false) + if ( +#ifndef _WIN32 + ctype == compiler_type::gcc ? cmaj > 4 || (cmaj == 4 && cmin >= 9) : +#else + ctype == compiler_type::gcc ? cmaj > 8 || (cmaj == 8 && cmin >= 1) : +#endif + ctype == compiler_type::clang ? cmaj > 3 || (cmaj == 3 && cmin >= 5) : + false) { if (!(find_option_prefix ("-fdiagnostics-color", args) || find_option ("-fno-diagnostics-color", args) || diff --git a/libbuild2/diagnostics.cxx b/libbuild2/diagnostics.cxx index e164f10..4a46756 100644 --- a/libbuild2/diagnostics.cxx +++ b/libbuild2/diagnostics.cxx @@ -3,9 +3,10 @@ #include -#include // strcmp(), strchr(), memcpy() +#include // strchr(), memcpy() #include // getenv() +#include // fdterm_color() #include #include @@ -30,7 +31,7 @@ namespace build2 bool diag_no_line = false; bool diag_no_column = false; - optional stderr_term = nullopt; + bool stderr_term = false; bool stderr_term_color = false; void @@ -50,29 +51,38 @@ namespace build2 diag_color_option = c; diag_no_line = nl; diag_no_column = nc; + stderr_term = st; if (st) { - stderr_term = std::getenv ("TERM"); - - stderr_term_color = + // @@ TMP: eventually we want to enable on Windows by default. + // #ifdef _WIN32 - // For now we disable color on Windows since it's unclear if/where/how - // it is supported. Maybe one day someone will figure this out. + if (c && *c) + { +#endif + stderr_term_color = fdterm_color (stderr_fd (), !c || *c /* enable */); + + // If the user specified --diag-color on POSIX we will trust the color + // is supported (e.g., wrong TERM value, etc). // - false + if (!stderr_term_color && c && *c) + { +#ifdef _WIN32 + fail << "unable to enable diagnostics color support for stderr"; #else - // This test was lifted from GCC (Emacs shell sets TERM=dumb). - // - *stderr_term != nullptr && strcmp (*stderr_term, "dumb") != 0 + stderr_term_color = true; +#endif + } + +#ifdef _WIN32 + } + else + stderr_term_color = false; #endif - ; } else - { - stderr_term = nullopt; stderr_term_color = false; - } } // Stream verbosity. diff --git a/libbuild2/utility.hxx b/libbuild2/utility.hxx index 43cb904..f37fc54 100644 --- a/libbuild2/utility.hxx +++ b/libbuild2/utility.hxx @@ -149,11 +149,9 @@ namespace build2 LIBBUILD2_SYMEXPORT extern bool diag_no_line; // --no-line LIBBUILD2_SYMEXPORT extern bool diag_no_column; // --no-column - // If stderr is not a terminal, then the value is absent (so can be used as - // bool). Otherwise, it is the value of the TERM environment variable (which - // can be NULL). + // True if stderr is a terminal. // - LIBBUILD2_SYMEXPORT extern optional stderr_term; + LIBBUILD2_SYMEXPORT extern bool stderr_term; // True if the color can be used on the stderr terminal. // -- cgit v1.1