From: Lars Gustäbel Date: Sun, 1 Nov 2009 18:39:58 +0000 (+0100) Subject: Use zlib compression for the cached files X-Git-Tag: v3.0pre0~190 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d7e33e81e239663cd4899e38fcc5ab704432d22;p=thirdparty%2Fccache.git Use zlib compression for the cached files See . --- diff --git a/Makefile.in b/Makefile.in index b29218242..6d8241f68 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/ccache.1 b/ccache.1 index 9d17578e6..f444a70eb 100644 --- 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 diff --git a/ccache.c b/ccache.c index ecca6f0cf..27cc45cd7 100644 --- 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); diff --git a/ccache.h b/ccache.h index 7ae4351e6..dc09d71f8 100644 --- a/ccache.h +++ b/ccache.h @@ -23,6 +23,10 @@ #include #endif +#ifdef ENABLE_ZLIB +#include +#endif + #define STATUS_NOTFOUND 3 #define STATUS_FATAL 4 #define STATUS_NOCACHE 5 @@ -36,6 +40,13 @@ #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, ...); diff --git a/ccache.yo b/ccache.yo index 4d0a960b6..b47b0eefa 100644 --- 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) diff --git a/config.h.in b/config.h.in index ffaf15840..2fde92065 100644 --- a/config.h.in +++ b/config.h.in @@ -105,6 +105,9 @@ /* 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 diff --git a/configure b/configure index 5586c37b5..851fabfc8 100755 --- 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 +_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 +_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 diff --git a/configure.in b/configure.in index fbeb97640..4db700995 100644 --- a/configure.in +++ b/configure.in @@ -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 index 000000000..7ef329dfa --- /dev/null +++ b/manage-cache.sh @@ -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 a0d975367..38f6826e2 100644 --- 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)