On Saturday 14 of June 2014, Joel Rosdahl wrote:
> Hi Lubos,
>
> Sorry about the ping delay. I've now looked at your patch and it looks
> promising.
...
> I suggest passing the argument list as an argument to the compiler_is_*
> functions instead of relying on global variables.
>
> When extracting the compiler name, I suggest using basename() from util.c.
> That way it will work on Windows as well.
Attached is an updated patch that passes also all the tests.
--
Lubos Lunak
From b466ec1fde17ff72989a39c51fbe3f1c68284967 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?=
Date: Fri, 29 Nov 2013 12:14:03 +0100
Subject: [PATCH] support compiler color diagnostics if possible
Clang and GCC (starting with 4.9) support color output if possible,
but since ccache redirects stderr to a file, they detect the output
is not a terminal and do not enable colors. Try to detect if colors
would be used and force colors explicitly.
Caveats:
- Compiles with and without colors are considered different from each
other (so they are "duplicated").
- GCC decided to roll its own name for the option, so it's necessary
to guess which compiler is actually used.
---
ccache.c | 79
1 file changed, 79 insertions(+)
diff --git a/ccache.c b/ccache.c
index e583329..49a6c53 100644
--- a/ccache.c
+++ b/ccache.c
@@ -1095,6 +1095,26 @@ hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
}
/*
+ * Note that these compiler checks are unreliable, so nothing should hard-depend on them.
+ */
+
+static bool compiler_is_clang(struct args *args)
+{
+ char* name = basename(args->argv[ 0 ]);
+ bool is = strstr( name, "clang" ) != NULL;
+ free(name);
+ return is;
+}
+
+static bool compiler_is_gcc(struct args *args)
+{
+ char* name = basename(args->argv[ 0 ]);
+ bool is = strstr(name, "gcc") != NULL || strstr(name, "g++") != NULL;
+ free(name);
+ return is;
+}
+
+/*
* Update a hash sum with information common for the direct and preprocessor
* modes.
*/
@@ -1158,6 +1178,15 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
}
free(p);
}
+
+ /* Possibly hash GCC_COLORS (for color diagnostics). */
+ if (compiler_is_gcc(args)) {
+ const char* gcc_colors = getenv("GCC_COLORS");
+ if (gcc_colors != NULL) {
+ hash_delimiter(hash,"gcccolors");
+ hash_string(hash, gcc_colors);
+ }
+ }
}
/*
@@ -1554,6 +1583,13 @@ is_precompiled_header(const char *path)
|| str_eq(get_extension(path), ".pth");
}
+static bool color_output_possible()
+{
+ const char* term_env = getenv("TERM");
+
+ return isatty(STDERR_FILENO) && term_env && strcasecmp(term_env, "DUMB") != 0;
+}
+
/*
* Process the compiler options into options suitable for passing to the
* preprocessor and the real compiler. The preprocessor options don't include
@@ -1582,6 +1618,7 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
int argc;
char **argv;
bool result = true;
+ bool found_color_diagnostics = false;
expanded_args = args_copy(args);
stripped_args = args_init(0, NULL);
@@ -1938,6 +1975,26 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
free(arg);
}
+ if (str_eq(argv[i], "-fcolor-diagnostics")
+ || str_eq(argv[i], "-fno-color-diagnostics")
+ || str_eq(argv[i], "-fdiagnostics-color")
+ || str_eq(argv[i], "-fdiagnostics-color=always")
+ || str_eq(argv[i], "-fno-diagnostics-color")
+ || str_eq(argv[i], "-fdiagnostics-color=never")) {
+ args_add(stripped_args, argv[i]);
+ found_color_diagnostics = true;
+ continue;
+ }
+ if (str_eq(argv[i], "-fdiagnostics-color=auto")) {
+ if (color_output_possible()) {
+/* Output is redirected, so color output must be forced. */
+args_add(stripped_args, "-fdiagnostics-color=always");
+cc_log("Automatically forcing colors");
+ }
+ found_color_diagnostics = true;
+ continue;
+ }
+
/*
* Options taking an argument that we may want to rewrite to relative paths
* to get better hit rate. A secondary effect is that paths in the standard
@@ -2228,6 +2285,28 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
}
/*
+ * Since output is redirected, compilers will not color their output by default,
+ * so force it explicitly if it would be otherwise done.
+ */
+ if (!found_color_diagnostics && color_output_possible()) {
+ if (compiler_is_clang(args)) {
+ args_add(stripped_args, "-fcolor-diagnostics");
+ cc_log("Automatically enabling colors");
+ } else if (compiler_is_gcc(args)) {
+ /*
+ * GCC has it since 4.9, but that'd require detecting what GCC
+ * version is used for the actual compile. However it requires
+ * also GCC_COLORS to be set (and not empty), so use that
+ * for detecting if GCC would use colors.
+ */
+ if (getenv("GCC_COLORS") != NULL && getenv("GCC_COLORS")[ 0 ] != '\0') {
+args_add(stripped_args, "-fdiagnostics-color");
+