]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Use zlib compression for the cached files
authorLars Gustäbel <lars@gustaebel.de>
Sun, 1 Nov 2009 18:39:58 +0000 (19:39 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Tue, 5 Jan 2010 17:53:00 +0000 (18:53 +0100)
See <http://www.gustaebel.de/lars/ccache/>.

Makefile.in
ccache.1
ccache.c
ccache.h
ccache.yo
config.h.in
configure
configure.in
manage-cache.sh [new file with mode: 0644]
util.c

index b29218242fe9ae6f5995605c26cbb9f37c36577e..6d8241f6826d0fd75e7842bc1a87bb229d2b9007 100644 (file)
@@ -13,6 +13,7 @@ CFLAGS=$(CPPFLAGS) @CFLAGS@
 LDFLAGS=@LDFLAGS@
 EXEEXT=@EXEEXT@
 
+LIBS= @LIBS@
 OBJS= ccache.o mdfour.o hash.o execute.o util.o args.o stats.o \
        cleanup.o snprintf.o unify.o
 HEADERS = ccache.h mdfour.h
@@ -22,7 +23,7 @@ all: ccache$(EXEEXT)
 docs: ccache.1 web/ccache-man.html
 
 ccache$(EXEEXT): $(OBJS) $(HEADERS)
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
 
 ccache.1: ccache.yo
        -yodl2man -o ccache.1 ccache.yo
index 9d17578e630d5dc67067cfdf79f831a3bfbc7817..f444a70eb3f892b50e726e70db813031aceb5c60 100644 (file)
--- a/ccache.1
+++ b/ccache.1
@@ -210,7 +210,8 @@ If you set the environment variable
 CCACHE_HARDLINK then ccache will attempt to use hard links from the
 cache directory when creating the compiler output rather than using a
 file copy\&. Using hard links is faster, but can confuse programs like
-\&'make\&' that rely on modification times\&.
+\&'make\&' that rely on modification times\&. Hard links are never made for
+compressed cache files\&.
 .IP 
 .IP "\fBCCACHE_RECACHE\fP" 
 This forces ccache to not use any cached
@@ -267,6 +268,11 @@ systems like this you can use the CCACHE_EXTENSION option to override
 the default\&. On HP-UX set this environment variable to "i" if you use
 the aCC compiler\&.
 .IP 
+.IP "\fBCCACHE_NOCOMPRESS\fP" 
+If you set the environment variable
+CCACHE_NOCOMPRESS then there is no compression used on files that go
+into the cache\&.
+.IP 
 .PP 
 .SH "CACHE SIZE MANAGEMENT" 
 .PP 
@@ -279,6 +285,14 @@ When these limits are reached ccache will reduce the cache to 20%
 below the numbers you specified in order to avoid doing the cache
 clean operation too often\&.
 .PP 
+.SH "CACHE COMPRESSION" 
+.PP 
+By default ccache will compress all files it puts into the cache
+using the zlib compression\&. While this involves a negligible
+performance slowdown, it significantly increases the number of files
+that fit in the cache\&. You can turn off compression setting the
+CCACHE_NOCOMPRESS environment variable\&.
+.PP 
 .SH "HOW IT WORKS" 
 .PP 
 The basic idea is to detect when you are compiling exactly the same
index ecca6f0cf5af883cbbbb34a643ddf59c6b8269df..27cc45cd76005d01f83d81e0aad9bfa6e4781158 100644 (file)
--- a/ccache.c
+++ b/ccache.c
@@ -199,7 +199,7 @@ static void to_cache(ARGS *args)
                fd = open(tmp_stderr, O_RDONLY | O_BINARY);
                if (fd != -1) {
                        if (strcmp(output_file, "/dev/null") == 0 ||
-                           rename(tmp_hashname, output_file) == 0 || errno == ENOENT) {
+                           move_file(tmp_hashname, output_file) == 0 || errno == ENOENT) {
                                if (cpp_stderr) {
                                        /* we might have some stderr from cpp */
                                        int fd2 = open(cpp_stderr, O_RDONLY | O_BINARY);
@@ -231,14 +231,25 @@ static void to_cache(ARGS *args)
        x_asprintf(&path_stderr, "%s.stderr", hashname);
 
        if (stat(tmp_stderr, &st1) != 0 ||
-           stat(tmp_hashname, &st2) != 0 ||
-           rename(tmp_hashname, hashname) != 0 ||
-           rename(tmp_stderr, path_stderr) != 0) {
+               stat(tmp_hashname, &st2) != 0 ||
+               move_file(tmp_hashname, hashname) != 0 ||
+               move_file(tmp_stderr, path_stderr) != 0) {
                cc_log("failed to rename tmp files - %s\n", strerror(errno));
                stats_update(STATS_ERROR);
                failed();
        }
 
+#if ENABLE_ZLIB
+       /* do an extra stat on the cache files for
+          the size statistics */
+       if (stat(path_stderr, &st1) != 0 ||
+               stat(hashname, &st2) != 0) {
+               cc_log("failed to stat cache files - %s\n", strerror(errno));
+               stats_update(STATS_ERROR);
+               failed();
+    }
+#endif
+
        cc_log("Placed %s into cache\n", output_file);
        stats_tocache(file_size(&st1) + file_size(&st2));
 
@@ -478,7 +489,13 @@ static void from_cache(int first)
        }
 
        /* the user might be disabling cache hits */
+#ifndef ENABLE_ZLIB
+       /* if the cache file is compressed we must recache */
+       if ((first && getenv("CCACHE_RECACHE")) ||
+               test_if_compressed(hashname) == 1) {
+#else
        if (first && getenv("CCACHE_RECACHE")) {
+#endif
                close(fd_stderr);
                unlink(stderr_file);
                free(stderr_file);
@@ -491,7 +508,9 @@ static void from_cache(int first)
                ret = 0;
        } else {
                unlink(output_file);
-               if (getenv("CCACHE_HARDLINK")) {
+               /* only make a hardlink if the cache file is uncompressed */
+               if (getenv("CCACHE_HARDLINK") &&
+                       test_if_compressed(hashname) == 0) {
                        ret = link(hashname, output_file);
                } else {
                        ret = copy_file(hashname, output_file);
index 7ae4351e61e10b422cf99c21fdbb75ea55b0ed7e..dc09d71f803523a70db634fd33be739e3cb21d46 100644 (file)
--- a/ccache.h
+++ b/ccache.h
 #include <pwd.h>
 #endif
 
+#ifdef ENABLE_ZLIB
+#include <zlib.h>
+#endif
+
 #define STATUS_NOTFOUND 3
 #define STATUS_FATAL 4
 #define STATUS_NOCACHE 5
 #define DEFAULT_MAXSIZE (1000*1000)
 #endif
 
+/* file copy mode */
+#ifdef ENABLE_ZLIB
+#define COPY_UNCOMPRESSED 0
+#define COPY_FROM_CACHE 1
+#define COPY_TO_CACHE 2
+#endif
+
 enum stats {
        STATS_NONE=0,
        STATS_STDOUT,
@@ -79,6 +90,8 @@ void fatal(const char *msg);
 
 void copy_fd(int fd_in, int fd_out);
 int copy_file(const char *src, const char *dest);
+int move_file(const char *src, const char *dest);
+int test_if_compressed(const char *filename);
 
 int create_dir(const char *dir);
 void x_asprintf(char **ptr, const char *format, ...);
index 4d0a960b60e5ccc10db1aa9913a9a63f71bf9fa5..b47b0eefa386ed506933cd73ab7eb9ba83385aed 100644 (file)
--- a/ccache.yo
+++ b/ccache.yo
@@ -169,6 +169,11 @@ will have problems with the intermediate filename extensions used in
 this optimisation, in which case this option could allow ccache to be
 used.
 
+dit(bf(CCACHE_NOCOMPRESS)) If you set the environment variable
+CCACHE_NOCOMPRESS then there is no compression used on files that go
+into the cache. However, this setting has no effect on how files are
+retrieved from the cache, compressed results will still be usable.
+
 dit(bf(CCACHE_NOSTATS)) If you set the environment variable
 CCACHE_NOSTATS then ccache will not update the statistics files on
 each compile.
@@ -181,7 +186,8 @@ dit(bf(CCACHE_HARDLINK)) If you set the environment variable
 CCACHE_HARDLINK then ccache will attempt to use hard links from the
 cache directory when creating the compiler output rather than using a
 file copy. Using hard links is faster, but can confuse programs like
-'make' that rely on modification times.
+'make' that rely on modification times. Hard links are never made for
+compressed cache files.
 
 dit(bf(CCACHE_RECACHE)) This forces ccache to not use any cached
 results, even if it finds them. New results are still cached, but
@@ -241,6 +247,14 @@ When these limits are reached ccache will reduce the cache to 20%
 below the numbers you specified in order to avoid doing the cache
 clean operation too often.
 
+manpagesection(CACHE COMPRESSION)
+
+By default ccache will compress all files it puts into the cache
+using the zlib compression. While this involves a negligible
+performance slowdown, it significantly increases the number of files
+that fit in the cache. You can turn off compression setting the
+CCACHE_NOCOMPRESS environment variable.
+
 manpagesection(HOW IT WORKS)
 
 The basic idea is to detect when you are compiling exactly the same
@@ -299,6 +313,8 @@ itemize(
   cache. This tells the filesystem to inherit group ownership for new
   directories. The command "chmod g+s `find $CCACHE_DIR -type d`" might
   be useful for this.
+  it() Set bf(CCACHE_NOCOMPRESS) for all users, if there are users with
+  versions of ccache that do not support compression.
 )
 
 manpagesection(HISTORY)
index ffaf15840a992eb36b0b802b31a42472eacea2d9..2fde920655a2e4a12f271e9387aada178c09ea32 100644 (file)
 /* Define _GNU_SOURCE so that we get all necessary prototypes */
 #undef _GNU_SOURCE
 
+/* Define to 1 if you like to have zlib compression for the ccache. */
+#undef ENABLE_ZLIB
+
 /* Define on UNIX to activate XPG/5 features.  */
 #if !defined(_XOPEN_SOURCE)
 # define _XOPEN_SOURCE
index 5586c37b55ac1fbab14ad1358c4486e81af05a18..851fabfc8ecf3fd80fa59cf00d3e2b23b9571327 100755 (executable)
--- a/configure
+++ b/configure
@@ -836,6 +836,11 @@ if test -n "$ac_init_help"; then
 
   cat <<\_ACEOF
 
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-zlib           enable zlib support for ccache compression
+
 Some influential environment variables:
   CC          C compiler command
   CFLAGS      C compiler flags
@@ -936,7 +941,7 @@ esac
     else
       echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
     fi
-    cd "$ac_popdir"
+    cd $ac_popdir
   done
 fi
 
@@ -1859,7 +1864,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -1917,7 +1923,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2033,7 +2040,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2087,7 +2095,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2132,7 +2141,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2176,7 +2186,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2614,7 +2625,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2686,7 +2698,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2740,7 +2753,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2811,7 +2825,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2865,7 +2880,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -2932,7 +2948,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3002,7 +3019,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3083,7 +3101,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3253,7 +3272,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3324,7 +3344,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3514,7 +3535,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3616,7 +3638,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3681,7 +3704,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   cat conftest.err >&5
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"                   || test ! -s conftest.err'
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
@@ -3778,6 +3802,229 @@ cat >>confdefs.h <<\_ACEOF
 #define HAVE_C99_VSNPRINTF 1
 _ACEOF
 
+fi
+
+# Check whether --enable-zlib or --disable-zlib was given.
+if test "${enable_zlib+set}" = set; then
+  enableval="$enable_zlib"
+
+else
+  enable_zlib=yes
+fi;
+
+if test x"$enable_zlib" = x"yes"; then
+    if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for zlib.h" >&5
+echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_zlib_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking zlib.h usability" >&5
+echo $ECHO_N "checking zlib.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <zlib.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking zlib.h presence" >&5
+echo $ECHO_N "checking zlib.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <zlib.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: zlib.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: zlib.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: zlib.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: zlib.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: zlib.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: zlib.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: zlib.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: zlib.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: zlib.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: zlib.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for zlib.h" >&5
+echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_zlib_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_zlib_h" >&6
+
+fi
+if test $ac_cv_header_zlib_h = yes; then
+  echo "$as_me:$LINENO: checking for gzdopen in -lz" >&5
+echo $ECHO_N "checking for gzdopen in -lz... $ECHO_C" >&6
+if test "${ac_cv_lib_z_gzdopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char gzdopen ();
+int
+main ()
+{
+gzdopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_z_gzdopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_z_gzdopen=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_z_gzdopen" >&5
+echo "${ECHO_T}$ac_cv_lib_z_gzdopen" >&6
+if test $ac_cv_lib_z_gzdopen = yes; then
+  LIBS="-lz $LIBS"; cat >>confdefs.h <<\_ACEOF
+#define ENABLE_ZLIB 1
+_ACEOF
+
+fi
+
+fi
+
+
 fi
 
           ac_config_files="$ac_config_files Makefile"
@@ -4573,6 +4820,11 @@ esac
   *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
   esac
 
+  if test x"$ac_file" != x-; then
+    { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    rm -f "$ac_file"
+  fi
   # Let's still pretend it is `configure' which instantiates (i.e., don't
   # use $as_me), people would be surprised to read:
   #    /* config.h.  Generated by config.status.  */
@@ -4611,12 +4863,6 @@ echo "$as_me: error: cannot find input file: $f" >&2;}
         fi;;
       esac
     done` || { (exit 1); exit 1; }
-
-  if test x"$ac_file" != x-; then
-    { echo "$as_me:$LINENO: creating $ac_file" >&5
-echo "$as_me: creating $ac_file" >&6;}
-    rm -f "$ac_file"
-  fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
   sed "$ac_vpsub
index fbeb97640bfdc0cddc4bcc10b953932a47072f18..4db700995187b96cad4a97da59a07b8f3b47021a 100644 (file)
@@ -76,5 +76,14 @@ if test x"$ccache_cv_HAVE_C99_VSNPRINTF" = x"yes"; then
     AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [ ])
 fi
 
+dnl Check for zlib.
+AC_ARG_ENABLE([zlib],
+              AS_HELP_STRING([--enable-zlib], [enable zlib support for ccache compression]),,
+              [enable_zlib=yes])
+
+if test x"$enable_zlib" = x"yes"; then
+    AC_CHECK_HEADER(zlib.h, AC_CHECK_LIB(z, gzdopen, LIBS="-lz $LIBS"; AC_DEFINE(ENABLE_ZLIB)))
+fi
+
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
diff --git a/manage-cache.sh b/manage-cache.sh
new file mode 100644 (file)
index 0000000..7ef329d
--- /dev/null
@@ -0,0 +1,68 @@
+#!/bin/bash
+#
+# 2004-05-12 lars@gustaebel.de
+
+CCACHE_DIR=${CCACHE_DIR:-$HOME/.ccache}
+
+echo "Do you want to compress or decompress the ccache in $CCACHE_DIR?"
+read -p "Type c or d: " mode
+
+if [ "$mode" != "c" ] && [ "$mode" != "d" ]
+then
+    exit 1
+fi
+
+is_compressed() {
+    test "$(head -c 2 $1)" = $'\x1f\x8b'
+    return $?
+}
+
+tmpfile=$(mktemp)
+
+for dir in 0 1 2 3 4 5 6 7 8 9 a b c d e f
+do
+    # process ccache subdir
+    echo -n "$dir "
+
+    # find cache files
+    find $CCACHE_DIR/$dir -type f -name '*-*' |
+    sort > $tmpfile
+
+    oldsize=$(cat $CCACHE_DIR/$dir/stats | cut -d ' ' -f 13)
+    newsize=0
+
+    while read file
+    do
+        # empty files will be ignored since compressing
+        # them makes them bigger
+        test $(stat -c %s $file) -eq 0 && continue
+
+        if [ $mode = c ]
+        then
+            if ! is_compressed $file
+            then
+                gzip $file
+                mv $file.gz $file
+            fi
+        else
+            if is_compressed $file
+            then
+                mv $file $file.gz
+                gzip -d $file.gz
+            fi
+        fi
+
+        # calculate new size statistic for this subdir
+        let newsize=$newsize+$(stat -c "%B*%b" $file)/1024
+    done < $tmpfile
+
+    # update statistic file
+    read -a numbers < $CCACHE_DIR/$dir/stats
+    numbers[12]=$newsize
+    echo "${numbers[*]} " > $CCACHE_DIR/$dir/stats
+done
+echo
+
+# clean up
+rm $tmpfile
+
diff --git a/util.c b/util.c
index a0d9753679fa71386ce96d10c9a858adfbb5032f..38f6826e2e5c65141642990a946ddd896711a3b2 100644 (file)
--- a/util.c
+++ b/util.c
@@ -44,6 +44,7 @@ void fatal(const char *msg)
        exit(1);
 }
 
+#ifndef ENABLE_ZLIB
 /* copy all data from one file descriptor to another */
 void copy_fd(int fd_in, int fd_out)
 {
@@ -57,6 +58,11 @@ void copy_fd(int fd_in, int fd_out)
        }
 }
 
+/* move a file using rename */
+int move_file(const char *src, const char *dest) {
+       return rename(src, dest);
+}
+
 /* copy a file - used when hard links don't work 
    the copy is done via a temporary file and atomic rename
 */
@@ -120,6 +126,174 @@ int copy_file(const char *src, const char *dest)
        return 0;
 }
 
+#else /* ENABLE_ZLIB */
+
+/* copy all data from one file descriptor to another
+   possibly decompressing it
+*/
+void copy_fd(int fd_in, int fd_out) {
+       char buf[10240];
+       int n;
+       gzFile gz_in;
+
+       gz_in = gzdopen(dup(fd_in), "rb");
+
+       if (!gz_in) {
+               fatal("Failed to copy fd");
+       }
+
+       while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
+               if (write(fd_out, buf, n) != n) {
+                       fatal("Failed to copy fd");
+               }
+       }
+}
+
+static int _copy_file(const char *src, const char *dest, int mode) {
+       int fd_in, fd_out;
+       gzFile gz_in, gz_out = NULL;
+       char buf[10240];
+       int n, ret;
+       char *tmp_name;
+       mode_t mask;
+       struct stat st;
+
+       x_asprintf(&tmp_name, "%s.XXXXXX", dest);
+
+       if (getenv("CCACHE_NOCOMPRESS")) {
+               mode = COPY_UNCOMPRESSED;
+       }
+
+       /* open source file */
+       fd_in = open(src, O_RDONLY);
+       if (fd_in == -1) {
+               return -1;
+       }
+
+       gz_in = gzdopen(fd_in, "rb");
+       if (!gz_in) {
+               close(fd_in);
+               return -1;
+       }
+
+       /* open destination file */
+       fd_out = mkstemp(tmp_name);
+       if (fd_out == -1) {
+               gzclose(gz_in);
+               free(tmp_name);
+               return -1;
+       }
+
+       if (mode == COPY_TO_CACHE) {
+               /* The gzip file format occupies at least 20 bytes. So
+                  it will always occupy an entire filesystem block,
+                  even for empty files.
+                  Since most stderr files will be empty, we turn off
+                  compression in this case to save space.
+               */
+               if (fstat(fd_in, &st) != 0) {
+                       gzclose(gz_in);
+                       close(fd_out);
+                       free(tmp_name);
+                       return -1;
+               }
+               if (file_size(&st) == 0) {
+                       mode = COPY_UNCOMPRESSED;
+               }
+       }
+
+       if (mode == COPY_TO_CACHE) {
+               gz_out = gzdopen(dup(fd_out), "wb");
+               if (!gz_out) {
+                       gzclose(gz_in);
+                       close(fd_out);
+                       free(tmp_name);
+                       return -1;
+               }
+       }
+
+       while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
+               if (mode == COPY_TO_CACHE) {
+                       ret = gzwrite(gz_out, buf, n);
+               } else {
+                       ret = write(fd_out, buf, n);
+               }
+               if (ret != n) {
+                       gzclose(gz_in);
+                       if (gz_out) {
+                               gzclose(gz_out);
+                       }
+                       close(fd_out);
+                       unlink(tmp_name);
+                       free(tmp_name);
+                       return -1;
+               }
+       }
+
+       gzclose(gz_in);
+       if (gz_out) {
+               gzclose(gz_out);
+       }
+
+       /* get perms right on the tmp file */
+       mask = umask(0);
+       fchmod(fd_out, 0666 & ~mask);
+       umask(mask);
+
+       /* the close can fail on NFS if out of space */
+       if (close(fd_out) == -1) {
+               unlink(tmp_name);
+               free(tmp_name);
+               return -1;
+       }
+
+       unlink(dest);
+
+       if (rename(tmp_name, dest) == -1) {
+               unlink(tmp_name);
+               free(tmp_name);
+               return -1;
+       }
+
+       free(tmp_name);
+
+       return 0;
+}
+
+/* move a file to the cache, compressing it */
+int move_file(const char *src, const char *dest) {
+       int ret;
+
+       ret = _copy_file(src, dest, COPY_TO_CACHE);
+       if (ret != -1) unlink(src);
+       return ret;
+}
+
+/* copy a file from the cache, decompressing it */
+int copy_file(const char *src, const char *dest) {
+       return _copy_file(src, dest, COPY_FROM_CACHE);
+}
+#endif /* ENABLE_ZLIB */
+
+/* test if a file is zlib compressed */
+int test_if_compressed(const char *filename) {
+       FILE *f;
+
+       f = fopen(filename, "rb");
+       if (!f) {
+               return 0;
+       }
+
+       /* test if file starts with 1F8B, which is zlib's
+        * magic number */
+       if ((fgetc(f) != 0x1f) || (fgetc(f) != 0x8b)) {
+               fclose(f);
+               return 0;
+       }
+       
+       fclose(f);
+       return 1;
+}
 
 /* make sure a directory exists */
 int create_dir(const char *dir)