]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add support for running a custom command to identify the compiler
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 10 Aug 2010 18:26:10 +0000 (20:26 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Wed, 11 Aug 2010 06:17:42 +0000 (08:17 +0200)
MANUAL.txt
ccache.c
ccache.h
perf.py
stats.c
test.sh
util.c

index 07480fdbc034db09507cb1e42055b68f8d563f31..d780fa41a6b41d90801d7adc21a9c6748e398d3e 100644 (file)
@@ -211,6 +211,32 @@ cases you won't need any of these as the defaults will be fine.
     compiler's source has not changed, or if the compiler only has changes that
     don't affect code generation). You should only use the *none* setting if
     you know what you are doing.
+_a command string_::
+    Hash the standard output and standard error output of the specified
+    command. The command is passed to +/bin/sh+ for execution. You can use
+    ``$compiler'' in the command string to refer to the compiler. Example
+    commands:
++
+--
+* +$compiler -v+
+* +$compiler -dumpmachine && $compiler -dumpversion+
+
+You should make sure that the specified command is as fast as possible since it
+will be run once for each ccache invocation.
+
+Identifying the compiler using a command is useful if you want to avoid cache
+misses when the compiler has been rebuilt but not changed.
+
+Another case is when the compiler (as seen by ccache) actually isn't the real
+compiler but another compiler wrapper -- in that case, the default *mtime*
+method will hash the mtime and size of the other compiler wrapper, which means
+that ccache won't be able to detect a compiler upgrade. Using a suitable
+command to identify the compiler is thus safer, but it's also slower, so you
+should consider continue using the *mtime* method in combination with
+*CCACHE_PREFIX* if possible. See
+<<_using_ccache_with_other_compiler_wrappers,USING CCACHE WITH OTHER COMPILER
+WRAPPERS>>.
+--
 --
 
 *CCACHE_CPP2*::
@@ -572,17 +598,20 @@ environment variable *CCACHE_PREFIX* to the name of the wrapper (e.g. *distcc*)
 and ccache will prefix the command line with the specified command when running
 the compiler.
 
-It is not recommended to use the form *ccache anotherwrapper compiler args* as
-the compilation command. It's also not recommended to use the masquerading
-technique for the other compiler wrapper. The reason is that ccache will in
-both cases hash the mtime of the other wrapper instead of the real compiler
-(see the *CCACHE_COMPILERCHECK* option), which means that:
+Unless you set *CCACHE_COMPILERCHECK* to a suitable command (see the
+description of that configuration option), it is not recommended to use the
+form *ccache anotherwrapper compiler args* as the compilation command. It's
+also not recommended to use the masquerading technique for the other compiler
+wrapper. The reason is that by default, ccache will in both cases hash the
+mtime and size of the other wrapper instead of the real compiler, which means
+that:
 
 * Compiler upgrades will not be detected properly.
 * The cached results will not be shared between compilations with and without
   the other wrapper.
-* ccache will needlessly invoke the other wrapper when running the
-  preprocessor.
+
+Another minor thing is that if *CCACHE_PREFIX* is not used, ccache will
+needlessly invoke the other wrapper when running the preprocessor.
 
 
 Bugs
index 5942e9a172a3c1837bd8b920330df0c821a21621..d78b2bd79eac24dd8ab75e07fa5406ef37bcba5d 100644 (file)
--- a/ccache.c
+++ b/ccache.c
@@ -32,6 +32,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
@@ -914,10 +915,47 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
        } else if (str_eq(compilercheck, "content")) {
                hash_delimiter(hash, "cc_content");
                hash_file(hash, args->argv[0]);
-       } else { /* mtime */
+       } else if (str_eq(compilercheck, "mtime")) {
                hash_delimiter(hash, "cc_mtime");
                hash_int(hash, st.st_size);
                hash_int(hash, st.st_mtime);
+       } else { /* command string */
+               char buf[8192];
+               static char compiler_env[1024];
+               size_t n;
+               char *command;
+               FILE *f;
+               int status;
+
+               cc_log("Running compiler check command: %s", compilercheck);
+               snprintf(compiler_env, sizeof(compiler_env),
+                        "compiler=%s", orig_args->argv[0]);
+               putenv(compiler_env);
+               command = format("{ %s ; } </dev/null 2>&1", compilercheck);
+               f = popen(command, "r");
+               free(command);
+               if (!f) {
+                       stats_update(STATS_COMPCHECK);
+                       fatal("Compiler check popen failed");
+               }
+               hash_delimiter(hash, "cc_command");
+               while (1) {
+                       n = fread(buf, 1, sizeof(buf), f);
+                       hash_buffer(hash, buf, n);
+                       if (n < sizeof(buf)) {
+                               if (feof(f)) {
+                                       break;
+                               } else {
+                                       stats_update(STATS_COMPCHECK);
+                                       fatal("Failed reading from compiler check command");
+                               }
+                       }
+               }
+               status = pclose(f);
+               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+                       stats_update(STATS_COMPCHECK);
+                       fatal("Compiler check command returned %d", WEXITSTATUS(status));
+               }
        }
 
        /*
index 9f3cc7c43df1b1e8bcd600cf4472a7b44c484910..1fca1f6afd0bbe8d83793c9d66f22b5655d798d3 100644 (file)
--- a/ccache.h
+++ b/ccache.h
@@ -52,6 +52,7 @@ enum stats {
        STATS_NOOUTPUT = 23,
        STATS_EMPTYOUTPUT = 24,
        STATS_BADEXTRAFILE = 25,
+       STATS_COMPCHECK = 26,
 
        STATS_END
 };
diff --git a/perf.py b/perf.py
index 6b8fb8ca64798a87a57c7e685d5446d68d4f059e..b2e1f2e911d3faf2afb605960ef7f53ce859f832 100755 (executable)
--- a/perf.py
+++ b/perf.py
@@ -79,6 +79,7 @@ def test(tmp_dir, options, compiler_args, source_file):
         fp.close()
 
     environment = {"CCACHE_DIR": ccache_dir, "PATH": environ["PATH"]}
+    environment["CCACHE_COMPILERCHECK"] = options.compilercheck
     if options.compression:
         environment["CCACHE_COMPRESS"] = "1"
     if options.hardlink:
@@ -204,6 +205,9 @@ def main(argv):
     op.add_option(
         "--ccache",
         help="location of ccache (default: %s)" % DEFAULT_CCACHE)
+    op.add_option(
+        "--compilercheck",
+        help="specify compilercheck (default: mtime)")
     op.add_option(
         "--compression",
         help="use compression",
@@ -236,6 +240,7 @@ def main(argv):
         action="store_true")
     op.set_defaults(
         ccache=DEFAULT_CCACHE,
+        compilercheck="mtime",
         directory=DEFAULT_DIRECTORY,
         times=DEFAULT_TIMES)
     (options, args) = op.parse_args(argv[1:])
@@ -259,6 +264,7 @@ def main(argv):
         print "Compilation command: %s -c -o %s.o" % (
             " ".join(args),
             splitext(argv[-1])[0])
+        print "Compilercheck:", options.compilercheck
         print "Compression:", on_off(options.compression)
         print "Hardlink:", on_off(options.hardlink)
         print "Nostats:", on_off(options.nostats)
diff --git a/stats.c b/stats.c
index 745ee568f01fc2e345595d69cec26b85c108cad8..49a5f4255386c2e3d2cc0f278da48bc4b6dba3cd 100644 (file)
--- a/stats.c
+++ b/stats.c
@@ -71,6 +71,7 @@ static struct {
        { STATS_MISSING,      "cache file missing             ", NULL, 0 },
        { STATS_ARGS,         "bad compiler arguments         ", NULL, 0 },
        { STATS_SOURCELANG,   "unsupported source language    ", NULL, 0 },
+       { STATS_COMPCHECK,    "compiler check failed          ", NULL, 0 },
        { STATS_CONFTEST,     "autoconf compile/link          ", NULL, 0 },
        { STATS_UNSUPPORTED,  "unsupported compiler option    ", NULL, 0 },
        { STATS_OUTSTDOUT,    "output to stdout               ", NULL, 0 },
diff --git a/test.sh b/test.sh
index 3ae0bb61a4c777ef37163e2c5adb2cbc1eae87b3..f2f155bada1667564f8f9d9e62a6f82722cc8d82 100755 (executable)
--- a/test.sh
+++ b/test.sh
@@ -388,6 +388,32 @@ EOF
     checkstat 'cache hit (preprocessed)' 2
     checkstat 'cache miss' 1
 
+    testname="compilercheck=command"
+    $CCACHE -z >/dev/null
+    backdate compiler.sh
+    CCACHE_COMPILERCHECK='echo $compiler' $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 0
+    checkstat 'cache miss' 1
+    echo "# Compiler upgrade" >>compiler.sh
+    CCACHE_COMPILERCHECK="echo ./compiler.sh" $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 1
+    checkstat 'cache miss' 1
+    CCACHE_COMPILERCHECK='echo bar >&2' $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 1
+    checkstat 'cache miss' 2
+    CCACHE_COMPILERCHECK='read x; echo -n b >&2; echo ar >&2' $CCACHE ./compiler.sh -c test1.c
+    checkstat 'cache hit (preprocessed)' 2
+    checkstat 'cache miss' 2
+
+    testname="compilercheck=unknown_command"
+    $CCACHE -z >/dev/null
+    backdate compiler.sh
+    CCACHE_COMPILERCHECK="unknown_command" $CCACHE ./compiler.sh -c test1.c 2>/dev/null
+    if [ "$?" -eq 0 ]; then
+        test_failed "Expected failure running unknown_command to verify compiler but was success"
+    fi
+    checkstat 'compiler check failed' 1
+
     testname="no object file"
     cat <<'EOF' >test_no_obj.c
 int test_no_obj;
diff --git a/util.c b/util.c
index 42adccb414c747a55a80a55d98c8201f4303e887..8a9860936249e689be1144d07eeaeb9ed97d42bd 100644 (file)
--- a/util.c
+++ b/util.c
@@ -140,16 +140,7 @@ fatal(const char *format, ...)
        vsnprintf(msg, sizeof(msg), format, ap);
        va_end(ap);
 
-       if (cache_logfile) {
-               if (!logfile) {
-                       logfile = fopen(cache_logfile, "a");
-               }
-               if (logfile) {
-                       fprintf(logfile, "[%-5d] FATAL: %s\n", (int)getpid(), msg);
-                       fflush(logfile);
-               }
-       }
-
+       cc_log("FATAL: %s", msg);
        fprintf(stderr, "ccache: FATAL: %s\n", msg);
 
        exit(1);