Imported Upstream version 3.5 upstream/3.5
authorJinWang An <jinwang.an@samsung.com>
Tue, 3 Aug 2021 07:25:11 +0000 (16:25 +0900)
committerJinWang An <jinwang.an@samsung.com>
Tue, 3 Aug 2021 07:25:11 +0000 (16:25 +0900)
70 files changed:
INSTALL.md
LICENSE.html
Makefile.in
README.md
configure
configure.ac
dev.mk.in
doc/AUTHORS.adoc
doc/AUTHORS.html
doc/MANUAL.adoc
doc/MANUAL.html
doc/NEWS.adoc
doc/NEWS.html
doc/ccache.1
m4/clang.m4 [new file with mode: 0644]
m4/feature_macros.m4
src/args.c
src/ccache.c
src/ccache.h
src/cleanup.c
src/compopt.c
src/conf.c
src/conf.h
src/confitems.gperf
src/confitems_lookup.c
src/envtoconfitems.gperf
src/envtoconfitems_lookup.c
src/execute.c
src/exitfn.c
src/getopt_long.c [deleted file]
src/hash.c
src/hash.h [new file with mode: 0644]
src/hashtable.c
src/hashtable.h
src/hashtable_itr.c
src/hashtable_itr.h
src/hashtable_private.h
src/hashutil.c
src/hashutil.h
src/language.c
src/manifest.c
src/mdfour.c
src/snprintf.c
src/stats.c
src/unify.c
src/unify.h [new file with mode: 0644]
src/util.c
src/version.c
src/zlib/gzguts.h
src/zlib/zlib.h
src/zlib/zutil.h
test/run
test/suites/base.bash
test/suites/cpp1.bash
test/suites/debug_prefix_map.bash
test/suites/direct.bash
test/suites/hardlink.bash
test/suites/masquerading.bash
test/suites/pch.bash
test/suites/sanitize_blacklist.bash [new file with mode: 0644]
unittest/framework.c
unittest/framework.h
unittest/main.c
unittest/test_args.c
unittest/test_argument_processing.c
unittest/test_compopt.c
unittest/test_conf.c
unittest/test_hash.c
unittest/test_hashutil.c
unittest/test_util.c

index be25d02807963b76ebbb7cd4b91403230013b675..e5e335d4da9dbd39f12cbcd3fbb25eafa472b39a 100644 (file)
@@ -1,10 +1,11 @@
-ccache installation
-===================
+ccache installation from release archive
+========================================
 
 Prerequisites
 -------------
 
-To build ccache, you need:
+To build ccache from a
+[release archive](https://ccache.samba.org/download.html), you need:
 
 - A C compiler (for instance GCC)
 
index 5b393131514f484db141ffd28c2038363f9c5bf1..f31f97fd8f573451d374afa0a8cfddc4dc18ad32 100644 (file)
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
 <head>\r
 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
-<meta name="generator" content="AsciiDoc 8.6.9" />\r
+<meta name="generator" content="AsciiDoc 8.6.10" />\r
 <title>ccache copyright and license</title>\r
 <style type="text/css">\r
 /* Shared CSS for AsciiDoc xhtml11 and html5 backends */\r
@@ -734,7 +735,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache copyright and license</h1>\r
-<span id="revnumber">version 3.4.3</span>\r
+<span id="revnumber">version 3.5</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -1205,9 +1206,9 @@ following license:</p></div>
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.4.3<br />\r
+Version 3.5<br />\r
 Last updated\r
- 2018-09-02 10:04:04 CEST\r
+ 2018-09-26 22:34:27 CEST\r
 </div>\r
 </div>\r
 </body>\r
index dd0fc571ff97802ae7e7c3295b717d38be75a2e3..175e440493fa1ad1cbc0515aa93583f9e8ef008f 100644 (file)
@@ -24,6 +24,11 @@ all_cflags = $(CFLAGS)
 all_cppflags = @DEFS@ -DSYSCONFDIR=$(sysconfdir) -I. -I$(srcdir)/src -I$(builddir)/unittest $(CPPFLAGS)
 extra_libs = @extra_libs@
 
+v_at_0 = yes
+v_at_ = $(v_at_0)
+quiet := $(v_at_$(V))
+Q=$(if $(quiet),@)
+
 non_3pp_sources = \
     src/args.c \
     src/ccache.c \
@@ -45,7 +50,7 @@ non_3pp_sources = \
 generated_sources = \
     src/version.c
 3pp_sources = \
-    src/getopt_long.c \
+    @getopt_long_c@ \
     src/hashtable.c \
     src/hashtable_itr.c \
     src/murmurhashneutral2.c \
@@ -95,17 +100,21 @@ files_to_distclean = Makefile config.h config.log config.status
 all: ccache$(EXEEXT)
 
 ccache$(EXEEXT): $(ccache_objs) $(extra_libs)
-       $(CC) $(all_cflags) -o $@ $(ccache_objs) $(LDFLAGS) $(extra_libs) $(LIBS)
+       $(if $(quiet),@echo "  LD       $@")
+       $(Q)$(CC) $(all_cflags) -o $@ $(ccache_objs) $(LDFLAGS) $(extra_libs) $(LIBS)
 
 ccache.1: doc/ccache.1
-       cp $< $@
+       $(if $(quiet),@echo "  CP       $@")
+       $(Q)cp $< $@
 
 .PHONY: install
-install: ccache$(EXEEXT) ccache.1
-       $(installcmd) -d $(DESTDIR)$(bindir)
-       $(installcmd) -m 755 ccache$(EXEEXT) $(DESTDIR)$(bindir)
-       $(installcmd) -d $(DESTDIR)$(mandir)/man1
-       -$(installcmd) -m 644 ccache.1 $(DESTDIR)$(mandir)/man1/
+install: ccache$(EXEEXT) @disable_man@ccache.1
+       $(if $(quiet),@echo "  INSTALL  ccache$(EXEEXT)")
+       $(Q)$(installcmd) -d $(DESTDIR)$(bindir)
+       $(Q)$(installcmd) -m 755 ccache$(EXEEXT) $(DESTDIR)$(bindir)
+@disable_man@  $(if $(quiet),@echo "  INSTALL  ccache.1")
+@disable_man@  $(Q)$(installcmd) -d $(DESTDIR)$(mandir)/man1
+@disable_man@  $(Q)-$(installcmd) -m 644 ccache.1 $(DESTDIR)$(mandir)/man1/
 
 .PHONY: clean
 clean:
@@ -114,10 +123,13 @@ clean:
 conf.c: confitems_lookup.c envtoconfitems_lookup.c
 
 $(zlib_objs): CPPFLAGS += -include config.h
+$(zlib_objs): CFLAGS += @no_implicit_fallthrough_warning@
 
 src/zlib/libz.a: $(zlib_objs)
-       $(AR) cr $@ $(zlib_objs)
-       $(RANLIB) $@
+       $(if $(quiet),@echo "  AR       $@")
+       $(Q)$(AR) cr $@ $(zlib_objs)
+       $(if $(quiet),@echo "  RANLIB   $@")
+       $(Q)$(RANLIB) $@
 
 .PHONY: perf
 perf: ccache$(EXEEXT)
@@ -125,20 +137,25 @@ perf: ccache$(EXEEXT)
 
 .PHONY: test
 test: ccache$(EXEEXT) unittest/run$(EXEEXT)
-       unittest/run$(EXEEXT)
-       CC='$(CC)' $(BASH) $(srcdir)/test/run
+       $(if $(quiet),@echo "  TEST     unittest/run$(EXEEXT)")
+       $(Q)unittest/run$(EXEEXT)
+       $(if $(quiet),@echo "  TEST     $(srcdir)/test/run")
+       $(Q)CC='$(CC)' $(BASH) $(srcdir)/test/run
 
 .PHONY: unittest
 unittest: unittest/run$(EXEEXT)
-       unittest/run$(EXEEXT)
+       $(if $(quiet),@echo "  TEST     $@")
+       $(Q)unittest/run$(EXEEXT)
 
 unittest/run$(EXEEXT): $(base_objs) $(test_objs) $(extra_libs)
-       $(CC) $(all_cflags) -o $@ $(base_objs) $(test_objs) $(LDFLAGS) $(extra_libs) $(LIBS)
+       $(if $(quiet),@echo "  LD       $@")
+       $(Q)$(CC) $(all_cflags) -o $@ $(base_objs) $(test_objs) $(LDFLAGS) $(extra_libs) $(LIBS)
 
 unittest/main.o: unittest/suites.h
 
 unittest/suites.h: $(test_suites) Makefile
-       ls $^ | grep -v Makefile | xargs sed -n 's/TEST_SUITE(\(.*\))/SUITE(\1)/p' >$@
+       $(if $(quiet),@echo "  GEN      $@")
+       $(Q)ls $^ | grep -v Makefile | xargs sed -n 's/TEST_SUITE(\(.*\))/SUITE(\1)/p' >$@
 
 .PHONY: check
 check: test
@@ -153,6 +170,7 @@ installcheck: ccache$(EXEEXT) unittest/run$(EXEEXT)
        CCACHE=$(bindir)/ccache CC='$(CC)' $(BASH) $(srcdir)/test/run
 
 .c.o:
-       $(CC) $(all_cppflags) $(all_cflags) -c -o $@ $<
+       $(if $(quiet),@echo "  CC       $@")
+       $(Q)$(CC) $(all_cppflags) $(all_cflags) -c -o $@ $<
 
 @include_dev_mk@
index d6b127d8fe1c3464226c3bc7f3baba7cec1d3248..63bed113ce9cd29c5bd861763841b651468fa1d9 100644 (file)
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@ ccache – a fast compiler cache
 ==============================
 
 [![Build Status](https://travis-ci.org/ccache/ccache.svg?branch=master)](https://travis-ci.org/ccache/ccache)
+[![Code Quality: Cpp](https://img.shields.io/lgtm/grade/cpp/g/ccache/ccache.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/ccache/ccache/context:cpp)
+[![Total Alerts](https://img.shields.io/lgtm/alerts/g/ccache/ccache.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/ccache/ccache/alerts)
 
 ccache is a compiler cache. It speeds up recompilation by caching the result of
 previous compilations and detecting when the same compilation is being done
index 9d416db031f59ef43266dfe2db3bf9bf7ee7abcd..74581d5f7b70b8b15b22d4ca80fc11182328cf14 100755 (executable)
--- a/configure
+++ b/configure
@@ -637,8 +637,11 @@ CPPFLAGS
 LDFLAGS
 CFLAGS
 CC
+disable_man
 test_suites
 include_dev_mk
+getopt_long_c
+no_implicit_fallthrough_warning
 extra_libs
 host_os
 host_vendor
@@ -690,7 +693,9 @@ SHELL'
 ac_subst_files=''
 ac_user_opts='
 enable_option_checking
+enable_more_warnings
 with_bundled_zlib
+enable_man
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1319,6 +1324,13 @@ if test -n "$ac_init_help"; then
 
   cat <<\_ACEOF
 
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-more-warnings  enable more compiler warnings
+  --disable-man           disable installing man pages
+
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
@@ -2350,6 +2362,9 @@ esac
 
 
 
+
+
+
 # The later defininition of _XOPEN_SOURCE disables certain features
 # on Linux, so we need _GNU_SOURCE to re-enable them (makedev, tm_zone).
 
@@ -2478,7 +2493,7 @@ $as_echo "#define _XOPEN_SOURCE 500" >>confdefs.h
       ;;
     *)
 
-$as_echo "#define _XOPEN_SOURCE 600" >>confdefs.h
+$as_echo "#define _XOPEN_SOURCE 700" >>confdefs.h
 
       ;;
   esac
@@ -2503,11 +2518,21 @@ $as_echo "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h
   esac
 
 
-$as_echo "#define _POSIX_C_SOURCE 200112L" >>confdefs.h
+$as_echo "#define _POSIX_C_SOURCE 200809L" >>confdefs.h
 
 
 fi
 
+# _AC_LANG_COMPILER_CLANG
+# ---------------------
+# Check whether the compiler for the current language is clang.
+# Adapted from standard autoconf function: _AC_LANG_COMPILER_GNU
+#
+# Note: clang also identifies itself as a GNU compiler (gcc 4.2.1)
+# for compatibility reasons, so that cannot be used to determine
+# _AC_LANG_COMPILER_CLANG
+
+
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -3298,6 +3323,36 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the clang C compiler" >&5
+$as_echo_n "checking whether we are using the clang C compiler... " >&6; }
+if ${ac_cv_c_compiler_clang+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __clang__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_clang=yes
+else
+  ac_compiler_clang=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_clang=$ac_compiler_clang
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_clang" >&5
+$as_echo "$ac_cv_c_compiler_clang" >&6; }
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
 if ${ac_cv_prog_cc_c99+:} false; then :
@@ -3997,13 +4052,28 @@ else
 fi
 
 
-# If GCC, turn on warnings.
-if test "x$GCC" = "xyes"; then
+# If GCC (or clang), turn on warnings.
+if test "$ac_compiler_gnu" = yes; then
     CFLAGS="$CFLAGS -Wall -W"
 else
     CFLAGS="$CFLAGS -O"
 fi
 
+# Check whether --enable-more_warnings was given.
+if test "${enable_more_warnings+set}" = set; then :
+  enableval=$enable_more_warnings;
+fi
+
+if test x${enable_more_warnings} = xyes; then
+    CFLAGS="$CFLAGS -Wextra -Wpedantic"
+    if test "$ac_compiler_clang" = yes; then
+        CFLAGS="$CFLAGS -Weverything"
+        CFLAGS="$CFLAGS -Wno-padded -Wno-disabled-macro-expansion -Wno-format-nonliteral"
+        CFLAGS="$CFLAGS -Wno-double-promotion -Wno-float-conversion"
+        CFLAGS="$CFLAGS -Wno-conversion -Wno-shorten-64-to-32 -Wno-sign-conversion"
+    fi
+fi
+
 
 ac_header_dirent=no
 for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
@@ -4648,6 +4718,10 @@ fi
 done
 
 
+if test x"$ac_cv_func_getopt_long" != x"yes"; then
+    getopt_long_c="src/getopt_long.c"
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compar_fn_t in stdlib.h" >&5
 $as_echo_n "checking for compar_fn_t in stdlib.h... " >&6; }
 if ${ccache_cv_COMPAR_FN_T+:} false; then :
@@ -5871,9 +5945,15 @@ $as_echo "$as_me: WARNING: using bundled zlib" >&2;}
         use_bundled_zlib=yes
     fi
 else
-    { $as_echo "$as_me:${as_lineno-$LINENO}: using bundled zlib as requested" >&5
+    if test x${with_bundled_zlib} = xno; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: using system zlib as requested" >&5
+$as_echo "$as_me: using system zlib as requested" >&6;}
+        use_bundled_zlib=no
+    else
+        { $as_echo "$as_me:${as_lineno-$LINENO}: using bundled zlib as requested" >&5
 $as_echo "$as_me: using bundled zlib as requested" >&6;}
-    use_bundled_zlib=yes
+        use_bundled_zlib=yes
+    fi
 fi
 
 if test x${use_bundled_zlib} = xyes; then
@@ -5884,6 +5964,15 @@ else
     LIBS="$LIBS -lz"
 fi
 
+# Check whether --enable-man was given.
+if test "${enable_man+set}" = set; then :
+  enableval=$enable_man;
+fi
+
+if test x${enable_man} = xno; then
+    disable_man='#'
+fi
+
 if test x${windows_os} = xyes; then
     LIBS="$LIBS -lws2_32"
     for ac_func in GetFinalPathNameByHandleW
@@ -6213,7 +6302,7 @@ $as_echo "$as_me: developer mode enabled" >&6;}
 
     include_dev_mk='include dev.mk'
     version=`(git --git-dir=$srcdir/.git describe --dirty 2>/dev/null || echo vunknown) | sed -e 's/v//' -e 's/-/+/' -e 's/-/_/g'`
-    echo "const char CCACHE_VERSION[] = \"$version\";" >src/version.c
+    echo "extern const char CCACHE_VERSION[]; const char CCACHE_VERSION[] = \"$version\";" >src/version.c
 else
     { $as_echo "$as_me:${as_lineno-$LINENO}: developer mode disabled" >&5
 $as_echo "$as_me: developer mode disabled" >&6;}
@@ -6222,9 +6311,36 @@ fi
 if test ! -f $srcdir/src/version.c -a ! -f src/version.c ; then
     { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to determine ccache version" >&5
 $as_echo "$as_me: WARNING: unable to determine ccache version" >&2;}
-    echo "const char CCACHE_VERSION[] = \"unknown\";" >src/version.c
+    echo "extern const char CCACHE_VERSION[]; const char CCACHE_VERSION[] = \"unknown\";" >src/version.c
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler supports -Wno-implicit-fallthrough" >&5
+$as_echo_n "checking whether C compiler supports -Wno-implicit-fallthrough... " >&6; }
+saved_cflags=$CFLAGS
+CFLAGS=-Wno-implicit-fallthrough
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    no_implicit_fallthrough_warning="-Wno-implicit-fallthrough"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+CFLAGS=$saved_cflags
+
 test_suites=`cd $srcdir && ls unittest/test_*.c | egrep -v 'BASE|BACKUP|LOCAL|REMOTE' | xargs echo`
 
 ac_config_files="$ac_config_files Makefile"
@@ -7513,9 +7629,22 @@ fi
 cat <<EOF >config.h.tmp
 #ifndef CCACHE_CONFIG_H
 #define CCACHE_CONFIG_H
+#ifdef __clang__
+#pragma clang diagnostic push
+#if __clang_major__ >= 4
+#pragma clang diagnostic ignored "-Wreserved-id-macro"
+#endif
+#endif
+
 EOF
 cat config.h >>config.h.tmp
-echo '#endif' >>config.h.tmp
+cat <<EOF >>config.h.tmp
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+#endif // ifndef CCACHE_CONFIG_H
+EOF
 mv config.h.tmp config.h
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: now build ccache by running make" >&5
index e2a348d97044f8a01bd0c7b456d163bf865277c0..eaa66e522c42fc88a224685c4e4b0cbcf637439d 100644 (file)
@@ -17,12 +17,18 @@ case $host in
 esac
 
 AC_SUBST(extra_libs)
+AC_SUBST(no_implicit_fallthrough_warning)
+AC_SUBST(getopt_long_c)
 AC_SUBST(include_dev_mk)
 AC_SUBST(test_suites)
+AC_SUBST(disable_man)
 
 m4_include(m4/feature_macros.m4)
+m4_include(m4/clang.m4)
 
 dnl Checks for programs.
+AC_PROG_CC
+_AC_LANG_COMPILER_CLANG
 AC_PROG_CC_C99
 if test "$ac_cv_prog_cc_c99" = no; then
     AC_MSG_ERROR(cannot find a C99-compatible compiler)
@@ -39,13 +45,26 @@ fi
 # Prefer bash, needed for test.sh
 AC_PATH_TOOL(BASH, bash, "/bin/bash")
 
-# If GCC, turn on warnings.
-if test "x$GCC" = "xyes"; then
+# If GCC (or clang), turn on warnings.
+if test "$ac_compiler_gnu" = yes; then
     CFLAGS="$CFLAGS -Wall -W"
 else
     CFLAGS="$CFLAGS -O"
 fi
 
+AC_ARG_ENABLE(more_warnings,
+  [AS_HELP_STRING([--enable-more-warnings],
+    [enable more compiler warnings])])
+if test x${enable_more_warnings} = xyes; then
+    CFLAGS="$CFLAGS -Wextra -Wpedantic"
+    if test "$ac_compiler_clang" = yes; then
+        CFLAGS="$CFLAGS -Weverything"
+        CFLAGS="$CFLAGS -Wno-padded -Wno-disabled-macro-expansion -Wno-format-nonliteral"
+        CFLAGS="$CFLAGS -Wno-double-promotion -Wno-float-conversion"
+        CFLAGS="$CFLAGS -Wno-conversion -Wno-shorten-64-to-32 -Wno-sign-conversion"
+    fi
+fi
+
 AC_HEADER_DIRENT
 AC_HEADER_TIME
 AC_HEADER_SYS_WAIT
@@ -66,6 +85,10 @@ AC_CHECK_FUNCS(strtok_r)
 AC_CHECK_FUNCS(unsetenv)
 AC_CHECK_FUNCS(utimes)
 
+if test x"$ac_cv_func_getopt_long" != x"yes"; then
+    getopt_long_c="src/getopt_long.c"
+fi
+
 AC_CACHE_CHECK([for compar_fn_t in stdlib.h],ccache_cv_COMPAR_FN_T, [
     AC_TRY_COMPILE(
         [#include <stdlib.h>],
@@ -114,8 +137,13 @@ if test x${with_bundled_zlib} = x; then
         use_bundled_zlib=yes
     fi
 else
-    AC_MSG_NOTICE(using bundled zlib as requested)
-    use_bundled_zlib=yes
+    if test x${with_bundled_zlib} = xno; then
+        AC_MSG_NOTICE(using system zlib as requested)
+        use_bundled_zlib=no
+    else
+        AC_MSG_NOTICE(using bundled zlib as requested)
+        use_bundled_zlib=yes
+    fi
 fi
 
 if test x${use_bundled_zlib} = xyes; then
@@ -126,6 +154,13 @@ else
     LIBS="$LIBS -lz"
 fi
 
+AC_ARG_ENABLE(man,
+  [AS_HELP_STRING([--disable-man],
+    [disable installing man pages])])
+if test x${enable_man} = xno; then
+    disable_man='#'
+fi
+
 dnl Linking on Windows needs ws2_32
 if test x${windows_os} = xyes; then
     LIBS="$LIBS -lws2_32"
@@ -163,16 +198,27 @@ if test ! -f $srcdir/dev_mode_disabled && test "$RUN_FROM_BUILD_FARM" != yes; th
     AC_CONFIG_FILES([dev.mk])
     include_dev_mk='include dev.mk'
     version=`(git --git-dir=$srcdir/.git describe --dirty 2>/dev/null || echo vunknown) | sed -e 's/v//' -e 's/-/+/' -e 's/-/_/g'`
-    echo "const char CCACHE_VERSION@<:@@:>@ = \"$version\";" >src/version.c
+    echo "extern const char CCACHE_VERSION@<:@@:>@; const char CCACHE_VERSION@<:@@:>@ = \"$version\";" >src/version.c
 else
     AC_MSG_NOTICE(developer mode disabled)
 fi
 
 if test ! -f $srcdir/src/version.c -a ! -f src/version.c ; then
     AC_MSG_WARN(unable to determine ccache version)
-    echo "const char CCACHE_VERSION@<:@@:>@ = \"unknown\";" >src/version.c
+    echo "extern const char CCACHE_VERSION@<:@@:>@; const char CCACHE_VERSION@<:@@:>@ = \"unknown\";" >src/version.c
 fi
 
+dnl Check for -Wno-implicit-fallthrough
+AC_MSG_CHECKING([whether C compiler supports -Wno-implicit-fallthrough])
+saved_cflags=$CFLAGS
+CFLAGS=-Wno-implicit-fallthrough
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+    [AC_MSG_RESULT([yes])]
+    [no_implicit_fallthrough_warning="-Wno-implicit-fallthrough"],
+    [AC_MSG_RESULT([no])]
+)
+CFLAGS=$saved_cflags
+
 dnl Find test suite files.
 test_suites=`cd $srcdir && ls unittest/test_*.c | egrep -v 'BASE|BACKUP|LOCAL|REMOTE' | xargs echo`
 
@@ -182,9 +228,22 @@ AC_OUTPUT
 cat <<EOF >config.h.tmp
 #ifndef CCACHE_CONFIG_H
 #define CCACHE_CONFIG_H
+#ifdef __clang__
+#pragma clang diagnostic push
+#if __clang_major__ >= 4
+#pragma clang diagnostic ignored "-Wreserved-id-macro"
+#endif
+#endif
+
 EOF
 cat config.h >>config.h.tmp
-echo '#endif' >>config.h.tmp
+cat <<EOF >>config.h.tmp
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+#endif // ifndef CCACHE_CONFIG_H
+EOF
 mv config.h.tmp config.h
 
 AC_MSG_NOTICE(now build ccache by running make)
index fd599b8229a9de2c7012d9c0811d0e6d6ba5354b..914786eefd90a9a84ad60fe2e5d055ffa78e963f 100644 (file)
--- a/dev.mk.in
+++ b/dev.mk.in
@@ -7,6 +7,8 @@ A2X = a2x
 ASCIIDOC = asciidoc
 CPPCHECK = cppcheck
 CPPCHECK_SUPPRESSIONS = misc/cppcheck-suppressions.txt
+SHELLCHECK = shellcheck
+SHELLCHECK_EXCLUDES = misc/shellcheck-excludes.txt
 SCAN_BUILD = scan-build
 DOCKER = docker
 GPERF = gperf
@@ -38,6 +40,7 @@ headers = \
     src/conf.h \
     src/counters.h \
     src/getopt_long.h \
+    src/hash.h \
     src/hashtable.h \
     src/hashtable_itr.h \
     src/hashtable_private.h \
@@ -48,6 +51,7 @@ headers = \
     src/mdfour.h \
     src/murmurhashneutral2.h \
     src/system.h \
+    src/unify.h \
     unittest/framework.h \
     unittest/util.h
 generated_headers = \
@@ -100,13 +104,14 @@ uncrustify_exclude_files = \
     src/snprintf.c
 
 ifneq ($(shell sed 's/.*"\(.*\)".*/\1/' src/version.c 2>/dev/null),$(version))
-  $(shell echo 'const char CCACHE_VERSION[] = "$(version)";' >src/version.c)
+  $(shell echo 'extern const char CCACHE_VERSION[]; const char CCACHE_VERSION[] = "$(version)";' >src/version.c)
 endif
 src/version.o: src/version.c
 
 %_lookup.c: %.gperf
-       $(GPERF) $< | awk '/#ifdef __GNUC__/ { ++i; if (i == 2) { print "static"; }} {print}' >$@
-       echo "static const size_t $$(echo $(notdir $*) | tr a-z A-Z)_TOTAL_KEYWORDS = $$(sed -nr 's/.*TOTAL_KEYWORDS = ([0-9]+).*/\1/p' $@);" >>$@
+       $(if $(quiet),@echo "  GPERF    $@")
+       $(Q)$(GPERF) $< | awk '/#ifdef __GNUC__/ { ++i; if (i == 2) { print "static"; }} {print}' >$@
+       $(Q)echo "static const size_t $$(echo $(notdir $*) | tr a-z A-Z)_TOTAL_KEYWORDS = $$(sed -nr 's/.*TOTAL_KEYWORDS = ([0-9]+).*/\1/p' $@);" >>$@
 
 .PHONY: dist
 dist: $(dist_archives)
@@ -164,16 +169,19 @@ docs: $(generated_docs)
 
 %.html: %.adoc
        @mkdir -p $(@D)
-       $(ASCIIDOC) -o $@ -a revnumber=$(version) -a toc -b xhtml11 $<
+       $(if $(quiet),@echo "  ASCIIDOC $@")
+       $(Q)$(ASCIIDOC) -o $@ -a revnumber=$(version) -a toc -b xhtml11 $<
 
 %.xml: %.adoc
        @mkdir -p $(@D)
 # Make literals stand out as bold in the man page:
-       $(ASCIIDOC) -a revnumber=$(version) -d manpage -b docbook -o - $< | \
+       $(if $(quiet),@echo "  ASCIIDOC $@")
+       $(Q)$(ASCIIDOC) -a revnumber=$(version) -d manpage -b docbook -o - $< | \
          perl -pe 's!<literal>(.*?)</literal>!<emphasis role="strong">\1</emphasis>!g' >$@
 
 doc/ccache.1: doc/MANUAL.xml
-       $(A2X) --doctype manpage --format manpage $<
+       $(if $(quiet),@echo "  A2X      $@")
+       $(Q)$(A2X) --doctype manpage --format manpage $<
 
 .PHONY: update-authors
 update-authors:
@@ -188,9 +196,13 @@ check-syntax:
 .PHONY: cppcheck
 cppcheck:
        $(CPPCHECK) --suppressions-list=$(CPPCHECK_SUPPRESSIONS) \
-         --inline-suppr -q --enable=all --force \
+         --inline-suppr -q --enable=all --force -I . \
          $(non_3pp_sources) src/main.c $(test_sources)
 
+.PHONY: shellcheck
+shellcheck: test/suites/*.bash
+       $(SHELLCHECK) --shell=bash --exclude=$(shell sed -e 's/:.*//' <$(SHELLCHECK_EXCLUDES) | grep -v '#' | tr '\n' ',' | sed -e 's/,$$//') $^
+
 .PHONY: uncrustify
 uncrustify:
        uncrustify -c misc/uncrustify.cfg --no-backup --replace $(filter-out $(uncrustify_exclude_files), $(base_sources)) $(test_sources)
index fa0eb7c7b49345c31fc1bd5c57b6df75d0468f0c..b423be385f1d1f0b65899d5b3e8f1a3dfe19bc60 100644 (file)
@@ -23,8 +23,11 @@ ccache is a collective work with contributions from many people, including:
 * David Givone <david@givone.net>
 * Edward Z. Yang <ezyang@fb.com>
 * Francois Marier <francois@debian.org>
+* Gabriel Scherer <gabriel.scherer@gmail.com>
 * Geert Bosch <geert@mongodb.com>
+* Geert Kloosterman <geert.kloosterman@brightcomputing.com>
 * Grigory Entin <grigorye@dins.ru>
+* Havard Graff <havard.graff@gmail.com>
 * Hongli Lai <hongli@phusion.nl>
 * Ivan Vaigult <i.vaigult@gmail.com>
 * Jiang Jiang <jiangj@opera.com>
@@ -51,6 +54,7 @@ ccache is a collective work with contributions from many people, including:
 * Michael Meeks <michael.meeks@suse.com>
 * Mihai Serban <mihai.serban@intel.com>
 * Mike Frysinger <vapier@gentoo.org>
+* Mike Gulick <mgulick@mathworks.com>
 * Mikhail Kolomeytsev <mkolom@yandex-team.ru>
 * Mostyn Bramley-Moore <mostyn@antipode.se>
 * Neil Mushell <nmushell@bloomberg.net>
@@ -66,12 +70,14 @@ ccache is a collective work with contributions from many people, including:
 * Per Nordlöw <per.nordlow@autoliv.com>
 * Peter Budai <peterbudai@hotmail.com>
 * Philippe Proulx <eeppeliteloop@gmail.com>
+* Rafael Kitover <rkitover@gmail.com>
 * Ramiro Polla <ramiro.polla@gmail.com>
 * Robin H. Johnson <robbat2@gentoo.org>
 * Rolf Bjarne Kvinge <rolf@xamarin.com>
 * RW <fbsd06@mlists.homeunix.com>
 * Ryan Brown <ryb@ableton.com>
 * Sam Gross <sgross@fb.com>
+* Thomas Otto <thomas.otto@psd-fs.de>
 * Thomas Röfer <Thomas.Roefer@dfki.de>
 * Timofei Kushnir <timophey@rdp.ru>
 * Tim Potter <tpot@samba.org>
@@ -82,6 +88,7 @@ ccache is a collective work with contributions from many people, including:
 * Ville Skyttä <ville.skytta@iki.fi>
 * William S Fulton <wsf@fultondesigns.co.uk>
 * Wilson Snyder <wsnyder@wsnyder.org>
+* Xavier RENE-CORAIL <xavier.renecorail@gmail.com>
 * Yiding Jia <yiding@fb.com>
 
 Thanks!
index 2613f30eaf82a4afd4f20497e8b97a6e18621d52..3d5ff7e037a709335367e8f7d63b0002c012fe4e 100644 (file)
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
 <head>\r
 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
-<meta name="generator" content="AsciiDoc 8.6.9" />\r
+<meta name="generator" content="AsciiDoc 8.6.10" />\r
 <title>ccache authors</title>\r
 <style type="text/css">\r
 /* Shared CSS for AsciiDoc xhtml11 and html5 backends */\r
@@ -734,7 +735,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache authors</h1>\r
-<span id="revnumber">version 3.4.3</span>\r
+<span id="revnumber">version 3.5</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -834,16 +835,31 @@ Francois Marier &lt;<a href="mailto:francois@debian.org">francois@debian.org</a>
 </li>\r
 <li>\r
 <p>\r
+Gabriel Scherer &lt;<a href="mailto:gabriel.scherer@gmail.com">gabriel.scherer@gmail.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Geert Bosch &lt;<a href="mailto:geert@mongodb.com">geert@mongodb.com</a>&gt;\r
 </p>\r
 </li>\r
 <li>\r
 <p>\r
+Geert Kloosterman &lt;<a href="mailto:geert.kloosterman@brightcomputing.com">geert.kloosterman@brightcomputing.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Grigory Entin &lt;<a href="mailto:grigorye@dins.ru">grigorye@dins.ru</a>&gt;\r
 </p>\r
 </li>\r
 <li>\r
 <p>\r
+Havard Graff &lt;<a href="mailto:havard.graff@gmail.com">havard.graff@gmail.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Hongli Lai &lt;<a href="mailto:hongli@phusion.nl">hongli@phusion.nl</a>&gt;\r
 </p>\r
 </li>\r
@@ -974,6 +990,11 @@ Mike Frysinger &lt;<a href="mailto:vapier@gentoo.org">vapier@gentoo.org</a>&gt;
 </li>\r
 <li>\r
 <p>\r
+Mike Gulick &lt;<a href="mailto:mgulick@mathworks.com">mgulick@mathworks.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Mikhail Kolomeytsev &lt;<a href="mailto:mkolom@yandex-team.ru">mkolom@yandex-team.ru</a>&gt;\r
 </p>\r
 </li>\r
@@ -1049,6 +1070,11 @@ Philippe Proulx &lt;<a href="mailto:eeppeliteloop@gmail.com">eeppeliteloop@gmail
 </li>\r
 <li>\r
 <p>\r
+Rafael Kitover &lt;<a href="mailto:rkitover@gmail.com">rkitover@gmail.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Ramiro Polla &lt;<a href="mailto:ramiro.polla@gmail.com">ramiro.polla@gmail.com</a>&gt;\r
 </p>\r
 </li>\r
@@ -1079,6 +1105,11 @@ Sam Gross &lt;<a href="mailto:sgross@fb.com">sgross@fb.com</a>&gt;
 </li>\r
 <li>\r
 <p>\r
+Thomas Otto &lt;<a href="mailto:thomas.otto@psd-fs.de">thomas.otto@psd-fs.de</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Thomas Röfer &lt;<a href="mailto:Thomas.Roefer@dfki.de">Thomas.Roefer@dfki.de</a>&gt;\r
 </p>\r
 </li>\r
@@ -1129,6 +1160,11 @@ Wilson Snyder &lt;<a href="mailto:wsnyder@wsnyder.org">wsnyder@wsnyder.org</a>&g
 </li>\r
 <li>\r
 <p>\r
+Xavier RENE-CORAIL &lt;<a href="mailto:xavier.renecorail@gmail.com">xavier.renecorail@gmail.com</a>&gt;\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
 Yiding Jia &lt;<a href="mailto:yiding@fb.com">yiding@fb.com</a>&gt;\r
 </p>\r
 </li>\r
@@ -1140,9 +1176,9 @@ Yiding Jia &lt;<a href="mailto:yiding@fb.com">yiding@fb.com</a>&gt;
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.4.3<br />\r
+Version 3.5<br />\r
 Last updated\r
- 2018-09-02 10:26:59 CEST\r
+ 2018-10-15 21:28:32 CEST\r
 </div>\r
 </div>\r
 </body>\r
index 5a36e8153e58650042fd131c422c38664921d85d..9ea080541bee22423196f0cc02e678a7dfe1612b 100644 (file)
@@ -262,7 +262,7 @@ IN DIFFERENT DIRECTORIES>>.
     This setting allows you to choose the number of directory levels in the
     cache directory. The default is 2. The minimum is 1 and the maximum is 8.
 
-*compiler* (*CCACHE_CC*)::
+*compiler* (*CCACHE_COMPILER* or (deprecated) *CCACHE_CC*)::
 
     This setting can be used to force the name of the compiler to use. If set
     to the empty string (which is the default), ccache works it out from the
@@ -350,6 +350,13 @@ WRAPPERS>>.
     compiled, but that sometimes doesn't work. For example, when using the
     ``aCC'' compiler on HP-UX, set the cpp extension to *i*.
 
+*debug* (*CCACHE_DEBUG* or *CCACHE_NODEBUG*, see <<_boolean_values,Boolean values>> above)::
+
+    If true, enable the debug mode. The debug mode creates per-object debug
+    files that are helpful when debugging unexpected cache misses. Note however
+    that ccache performance will be reduced slightly. See
+    <<_cache_debugging_,debugging>> for more information. The default is false.
+
 *direct_mode* (*CCACHE_DIRECT* or *CCACHE_NODIRECT*, see <<_boolean_values,Boolean values>> above)::
 
     If true, the direct mode will be used. The default is true. See
@@ -451,6 +458,14 @@ might be incorrect.
     matching the compiler name in the normal *PATH* that isn't a symbolic link
     to ccache itself.
 
+*pch_external_checksum* (*CCACHE_PCH_EXTSUM* or *CCACHE_NOPCH_EXTSUM*, see <<_boolean_values,Boolean values>> above)::
+
+    When this option is set, and ccache finds a precompiled header file,
+    ccache will look for a file with the extension ``.sum'' added
+    (e.g. ``pre.h.gch.sum''), and if found, it will hash this file instead
+    of the precompiled header itself to work around the performance
+    penalty of hashing very large files.
+
 *prefix_command* (*CCACHE_PREFIX*)::
 
     This option adds a list of prefixes (separated by space) to the command
@@ -517,6 +532,9 @@ still has to do _some_ preprocessing (like macros).
     ccache normally examines a file's contents to determine whether it matches
     the cached version. With this option set, ccache will consider a file as
     matching its cached version if the mtimes and ctimes match.
+*file_stat_matches_ctime*::
+    Ignore ctimes when *file_stat_matches* is enabled. This can be useful when
+    backdating files' mtimes in a controlled way.
 *include_file_ctime*::
     By default, ccache also will not cache a file if it includes a header whose
     ctime is too new. This option disables that check.
@@ -728,6 +746,12 @@ The compiler was instructed to write its output to standard output using *-o
 | preprocessor error |
 Preprocessing the source code using the compiler's *-E* option failed.
 
+| stats updated |
+When statistics were updated the last time.
+
+| stats zeroed |
+When *ccache -z* was called the last time.
+
 | unsupported code directive |
 Code like the assembler *.incbin* directive was found. This is not supported
 by ccache.
@@ -839,6 +863,57 @@ Based on the hash, the cached compilation result can be looked up directly in
 the cache.
 
 
+Cache debugging
+---------------
+
+To find out what information ccache actually is hashing, you can enable the
+debug mode via the configuration setting *debug* or by setting *CCACHE_DEBUG*
+in the environment. This can be useful if you are investigating why you don't
+get cache hits. Note that performance will be reduced slightly.
+
+When the debug mode is enabled, ccache will create up to five additional files
+next to the object file:
+
+[options="header",cols="30%,70%"]
+|==============================================================================
+|Filename | Description
+| *<objectfile>.ccache-input-c* |
+Binary input hashed by both the direct mode and the preprocessor mode.
+
+| *<objectfile>.ccache-input-d* |
+Binary input only hashed by the direct mode.
+
+| *<objectfile>.ccache-input-p* |
+Binary input only hashed by the preprocessor mode.
+
+| *<objectfile>.ccache-input-text* |
+Human-readable combined diffable text version of the three files above.
+
+| *<objectfile>.ccache-log* |
+Log for this object file.
+
+|==============================================================================
+
+In the direct mode, ccache uses the MD4 hash of the *ccache-input-c*
++ *ccache-input-d* data (where *+* means concatenation), while the
+*ccache-input-c* + *ccache-input-p* data is used in the preprocessor mode.
+
+The *ccache-input-text* file is a combined text version of the three
+binary input files. It has three sections (“COMMON”, “DIRECT MODE” and
+“PREPROCESSOR MODE”), which is turn contain annotations that say what kind of
+data comes next.
+
+To debug why you don’t get an expected cache hit for an object file, you can do
+something like this:
+
+1. Build with debug mode enabled.
+2. Save the *<objectfile>.ccache-&#42;* files.
+3. Build again with debug mode enabled.
+4. Compare *<objectfile>.ccache-input-text* for the two builds. This together
+   with the *<objectfile>.ccache-log* files should give you some clues about
+   what is happening.
+
+
 Compiling in different directories
 ----------------------------------
 
index f9c3049a5a7deea4eacad1e46cb30a4f12da5d35..d9084bc14ebcb7420494a12fdeea911bedde7fcf 100644 (file)
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
 <head>\r
 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
-<meta name="generator" content="AsciiDoc 8.6.9" />\r
+<meta name="generator" content="AsciiDoc 8.6.10" />\r
 <title>CCACHE(1)</title>\r
 <style type="text/css">\r
 /* Shared CSS for AsciiDoc xhtml11 and html5 backends */\r
@@ -734,7 +735,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>CCACHE(1)</h1>\r
-<span id="revnumber">version 3.4.3</span>\r
+<span id="revnumber">version 3.5</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -1111,7 +1112,7 @@ setting key.</p></div>
 </p>\r
 </dd>\r
 <dt class="hdlist1">\r
-<strong>compiler</strong> (<strong>CCACHE_CC</strong>)\r
+<strong>compiler</strong> (<strong>CCACHE_COMPILER</strong> or (deprecated) <strong>CCACHE_CC</strong>)\r
 </dt>\r
 <dd>\r
 <p>\r
@@ -1247,6 +1248,17 @@ the <strong>prefix_command</strong> setting if possible. See
 </p>\r
 </dd>\r
 <dt class="hdlist1">\r
+<strong>debug</strong> (<strong>CCACHE_DEBUG</strong> or <strong>CCACHE_NODEBUG</strong>, see <a href="#_boolean_values">Boolean values</a> above)\r
+</dt>\r
+<dd>\r
+<p>\r
+    If true, enable the debug mode. The debug mode creates per-object debug\r
+    files that are helpful when debugging unexpected cache misses. Note however\r
+    that ccache performance will be reduced slightly. See\r
+    <a href="#_cache_debugging_">debugging</a> for more information. The default is false.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
 <strong>direct_mode</strong> (<strong>CCACHE_DIRECT</strong> or <strong>CCACHE_NODIRECT</strong>, see <a href="#_boolean_values">Boolean values</a> above)\r
 </dt>\r
 <dd>\r
@@ -1409,6 +1421,18 @@ might be incorrect.</p></div>
 </p>\r
 </dd>\r
 <dt class="hdlist1">\r
+<strong>pch_external_checksum</strong> (<strong>CCACHE_PCH_EXTSUM</strong> or <strong>CCACHE_NOPCH_EXTSUM</strong>, see <a href="#_boolean_values">Boolean values</a> above)\r
+</dt>\r
+<dd>\r
+<p>\r
+    When this option is set, and ccache finds a precompiled header file,\r
+    ccache will look for a file with the extension &#8220;.sum&#8221; added\r
+    (e.g. &#8220;pre.h.gch.sum&#8221;), and if found, it will hash this file instead\r
+    of the precompiled header itself to work around the performance\r
+    penalty of hashing very large files.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
 <strong>prefix_command</strong> (<strong>CCACHE_PREFIX</strong>)\r
 </dt>\r
 <dd>\r
@@ -1513,6 +1537,15 @@ still has to do <em>some</em> preprocessing (like macros).</p></div>
 </p>\r
 </dd>\r
 <dt class="hdlist1">\r
+<strong>file_stat_matches_ctime</strong>\r
+</dt>\r
+<dd>\r
+<p>\r
+    Ignore ctimes when <strong>file_stat_matches</strong> is enabled. This can be useful when\r
+    backdating files' mtimes in a controlled way.\r
+</p>\r
+</dd>\r
+<dt class="hdlist1">\r
 <strong>include_file_ctime</strong>\r
 </dt>\r
 <dd>\r
@@ -1818,6 +1851,14 @@ node).</p></td>
 <td align="left" valign="top"><p class="table">Preprocessing the source code using the compiler&#8217;s <strong>-E</strong> option failed.</p></td>\r
 </tr>\r
 <tr>\r
+<td align="left" valign="top"><p class="table">stats updated</p></td>\r
+<td align="left" valign="top"><p class="table">When statistics were updated the last time.</p></td>\r
+</tr>\r
+<tr>\r
+<td align="left" valign="top"><p class="table">stats zeroed</p></td>\r
+<td align="left" valign="top"><p class="table">When <strong>ccache -z</strong> was called the last time.</p></td>\r
+</tr>\r
+<tr>\r
 <td align="left" valign="top"><p class="table">unsupported code directive</p></td>\r
 <td align="left" valign="top"><p class="table">Code like the assembler <strong>.incbin</strong> directive was found. This is not supported\r
 by ccache.</p></td>\r
@@ -2013,6 +2054,87 @@ the cache.</p></div>
 </div>\r
 </div>\r
 <div class="sect1">\r
+<h2 id="_cache_debugging">Cache debugging</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>To find out what information ccache actually is hashing, you can enable the\r
+debug mode via the configuration setting <strong>debug</strong> or by setting <strong>CCACHE_DEBUG</strong>\r
+in the environment. This can be useful if you are investigating why you don&#8217;t\r
+get cache hits. Note that performance will be reduced slightly.</p></div>\r
+<div class="paragraph"><p>When the debug mode is enabled, ccache will create up to five additional files\r
+next to the object file:</p></div>\r
+<div class="tableblock">\r
+<table rules="all"\r
+width="100%"\r
+frame="border"\r
+cellspacing="0" cellpadding="4">\r
+<col width="30%" />\r
+<col width="70%" />\r
+<thead>\r
+<tr>\r
+<th align="left" valign="top">Filename </th>\r
+<th align="left" valign="top"> Description</th>\r
+</tr>\r
+</thead>\r
+<tbody>\r
+<tr>\r
+<td align="left" valign="top"><p class="table"><strong>&lt;objectfile&gt;.ccache-input-c</strong></p></td>\r
+<td align="left" valign="top"><p class="table">Binary input hashed by both the direct mode and the preprocessor mode.</p></td>\r
+</tr>\r
+<tr>\r
+<td align="left" valign="top"><p class="table"><strong>&lt;objectfile&gt;.ccache-input-d</strong></p></td>\r
+<td align="left" valign="top"><p class="table">Binary input only hashed by the direct mode.</p></td>\r
+</tr>\r
+<tr>\r
+<td align="left" valign="top"><p class="table"><strong>&lt;objectfile&gt;.ccache-input-p</strong></p></td>\r
+<td align="left" valign="top"><p class="table">Binary input only hashed by the preprocessor mode.</p></td>\r
+</tr>\r
+<tr>\r
+<td align="left" valign="top"><p class="table"><strong>&lt;objectfile&gt;.ccache-input-text</strong></p></td>\r
+<td align="left" valign="top"><p class="table">Human-readable combined diffable text version of the three files above.</p></td>\r
+</tr>\r
+<tr>\r
+<td align="left" valign="top"><p class="table"><strong>&lt;objectfile&gt;.ccache-log</strong></p></td>\r
+<td align="left" valign="top"><p class="table">Log for this object file.</p></td>\r
+</tr>\r
+</tbody>\r
+</table>\r
+</div>\r
+<div class="paragraph"><p>In the direct mode, ccache uses the MD4 hash of the <strong>ccache-input-c</strong>\r
++ <strong>ccache-input-d</strong> data (where <strong>+</strong> means concatenation), while the\r
+<strong>ccache-input-c</strong> + <strong>ccache-input-p</strong> data is used in the preprocessor mode.</p></div>\r
+<div class="paragraph"><p>The <strong>ccache-input-text</strong> file is a combined text version of the three\r
+binary input files. It has three sections (“COMMON”, “DIRECT MODE” and\r
+“PREPROCESSOR MODE”), which is turn contain annotations that say what kind of\r
+data comes next.</p></div>\r
+<div class="paragraph"><p>To debug why you don’t get an expected cache hit for an object file, you can do\r
+something like this:</p></div>\r
+<div class="olist arabic"><ol class="arabic">\r
+<li>\r
+<p>\r
+Build with debug mode enabled.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Save the <strong>&lt;objectfile&gt;.ccache-&#42;</strong> files.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Build again with debug mode enabled.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Compare <strong>&lt;objectfile&gt;.ccache-input-text</strong> for the two builds. This together\r
+   with the <strong>&lt;objectfile&gt;.ccache-log</strong> files should give you some clues about\r
+   what is happening.\r
+</p>\r
+</li>\r
+</ol></div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
 <h2 id="_compiling_in_different_directories">Compiling in different directories</h2>\r
 <div class="sectionbody">\r
 <div class="paragraph"><p>Some information included in the hash that identifies a unique compilation can\r
@@ -2473,9 +2595,9 @@ maintained by Joel Rosdahl. See AUTHORS.txt or AUTHORS.html and
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.4.3<br />\r
+Version 3.5<br />\r
 Last updated\r
- 2018-09-02 10:02:30 CEST\r
+ 2018-10-07 20:43:01 CEST\r
 </div>\r
 </div>\r
 </body>\r
index c2187f26a778b2739e100fe88647a0a6da678e73..aaa45cbb4b69596ec0114226f0e0c5690c2a1919 100644 (file)
@@ -1,6 +1,56 @@
 ccache news
 ===========
 
+ccache 3.5
+----------
+Release date: 2018-10-15
+
+Changes
+~~~~~~~
+
+- Added a boolean `debug` (`CCACHE_DEBUG`) configuration option. When enabled,
+  ccache will create per-object debug files that are helpful e.g. when
+  debugging unexpected cache misses. See also the new ``Cache debugging''
+  section in the manual.
+
+- Renamed `CCACHE_CC` to `CCACHE_COMPILER` (keeping the former as a deprecated
+  alias).
+
+- Added a new command-line option `-k/--get-config` that prints the value of a
+  config key.
+
+- It is now possible to let ccache hash a precomputed checksum file instead of
+  the full content of a precompiled header. This can save time for large
+  precompiled headers. Note that the build system needs to keep the checksum
+  file in sync with the precompiled header for this to work.
+
+- Improved performance substantially when using `hash_dir = false` on platforms
+  like macOS where `getcwd()` is slow.
+
+- Added ``stats updated'' timestamp in `ccache -s` output. This can be useful
+  if you wonder whether ccache actually was used for your last build.
+
+- Renamed ``stats zero time'' to ``stats zeroed'' and documented it. The
+  counter is also now only present in `ccache -s` output when `ccache -z`
+  actually has been called.
+
+- The content of the `-fsanitize-blacklist` file is now included in the hash,
+  so updates to the file will now correctly result in separate cache entries.
+
+- It's now possible to opt out of building and installing man pages when
+  running `make install` in the source repository.
+
+- If the compiler type can't be detected (e.g. if it is named *cc*), use safer
+  defaults that won't trip up Clang.
+
+- Made the ccache test suite work on FreeBSD.
+
+- Added `file_stat_matches_ctime` option to disable ctime check if
+  `file_stat_matches` is enabled.
+
+- Made “./configure --without-bundled-zlib” do what’s intended.
+
+
 ccache 3.4.3
 -----------
 Release date: 2018-09-02
@@ -11,11 +61,11 @@ Bug fixes
 - Fixed a race condition when creating the initial config file in the cache
   directory.
 
-- Bail out on too hard clang option `-MJ`.
+- Bail out on too hard Clang option `-MJ`.
 
 - Bail out on too hard option `-save-temps=obj`.
 
-- Handle separate parameter to clang option `-target` correctly.
+- Handle separate parameter to Clang option `-target` correctly.
 
 - Upgraded bundled zlib to version 1.2.11.
 
index c7f8933402281de6d90a26927bdb40fa6ebdb326..0530a6c4a4961616098ffdc1f7d5c746c4d0ab20 100644 (file)
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"\r
     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\r
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">\r
 <head>\r
 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />\r
-<meta name="generator" content="AsciiDoc 8.6.9" />\r
+<meta name="generator" content="AsciiDoc 8.6.10" />\r
 <title>ccache news</title>\r
 <style type="text/css">\r
 /* Shared CSS for AsciiDoc xhtml11 and html5 backends */\r
@@ -734,7 +735,7 @@ asciidoc.install(2);
 <body class="article">\r
 <div id="header">\r
 <h1>ccache news</h1>\r
-<span id="revnumber">version 3.4.3</span>\r
+<span id="revnumber">version 3.5</span>\r
 <div id="toc">
   <div id="toctitle">Table of Contents</div>
   <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
@@ -742,6 +743,98 @@ asciidoc.install(2);
 </div>\r
 <div id="content">\r
 <div class="sect1">\r
+<h2 id="_ccache_3_5">ccache 3.5</h2>\r
+<div class="sectionbody">\r
+<div class="paragraph"><p>Release date: 2018-10-15</p></div>\r
+<div class="sect2">\r
+<h3 id="_changes">Changes</h3>\r
+<div class="ulist"><ul>\r
+<li>\r
+<p>\r
+Added a boolean <code>debug</code> (<code>CCACHE_DEBUG</code>) configuration option. When enabled,\r
+  ccache will create per-object debug files that are helpful e.g. when\r
+  debugging unexpected cache misses. See also the new &#8220;Cache debugging&#8221;\r
+  section in the manual.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Renamed <code>CCACHE_CC</code> to <code>CCACHE_COMPILER</code> (keeping the former as a deprecated\r
+  alias).\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added a new command-line option <code>-k/--get-config</code> that prints the value of a\r
+  config key.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+It is now possible to let ccache hash a precomputed checksum file instead of\r
+  the full content of a precompiled header. This can save time for large\r
+  precompiled headers. Note that the build system needs to keep the checksum\r
+  file in sync with the precompiled header for this to work.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Improved performance substantially when using <code>hash_dir = false</code> on platforms\r
+  like macOS where <code>getcwd()</code> is slow.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added &#8220;stats updated&#8221; timestamp in <code>ccache -s</code> output. This can be useful\r
+  if you wonder whether ccache actually was used for your last build.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Renamed &#8220;stats zero time&#8221; to &#8220;stats zeroed&#8221; and documented it. The\r
+  counter is also now only present in <code>ccache -s</code> output when <code>ccache -z</code>\r
+  actually has been called.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+The content of the <code>-fsanitize-blacklist</code> file is now included in the hash,\r
+  so updates to the file will now correctly result in separate cache entries.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+It&#8217;s now possible to opt out of building and installing man pages when\r
+  running <code>make install</code> in the source repository.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+If the compiler type can&#8217;t be detected (e.g. if it is named <strong>cc</strong>), use safer\r
+  defaults that won&#8217;t trip up Clang.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Made the ccache test suite work on FreeBSD.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Added <code>file_stat_matches_ctime</code> option to disable ctime check if\r
+  <code>file_stat_matches</code> is enabled.\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
+Made “./configure --without-bundled-zlib” do what’s intended.\r
+</p>\r
+</li>\r
+</ul></div>\r
+</div>\r
+</div>\r
+</div>\r
+<div class="sect1">\r
 <h2 id="_ccache_3_4_3">ccache 3.4.3</h2>\r
 <div class="sectionbody">\r
 <div class="paragraph"><p>Release date: 2018-09-02</p></div>\r
@@ -756,7 +849,7 @@ Fixed a race condition when creating the initial config file in the cache
 </li>\r
 <li>\r
 <p>\r
-Bail out on too hard clang option <code>-MJ</code>.\r
+Bail out on too hard Clang option <code>-MJ</code>.\r
 </p>\r
 </li>\r
 <li>\r
@@ -766,7 +859,7 @@ Bail out on too hard option <code>-save-temps=obj</code>.
 </li>\r
 <li>\r
 <p>\r
-Handle separate parameter to clang option <code>-target</code> correctly.\r
+Handle separate parameter to Clang option <code>-target</code> correctly.\r
 </p>\r
 </li>\r
 <li>\r
@@ -3037,9 +3130,9 @@ Statistics counters are now correctly updated for -E option failures and
 <div id="footnotes"><hr /></div>\r
 <div id="footer">\r
 <div id="footer-text">\r
-Version 3.4.3<br />\r
+Version 3.5<br />\r
 Last updated\r
- 2018-09-02 10:22:59 CEST\r
+ 2018-10-15 21:28:32 CEST\r
 </div>\r
 </div>\r
 </body>\r
index b4b337778c88f0983750f659c1565c706335e350..94c6ab7fd1801e50e9319b225bb7b37ee2d85d98 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: ccache
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 09/02/2018
+.\"      Date: 10/15/2018
 .\"    Manual: ccache Manual
-.\"    Source: ccache 3.4.3
+.\"    Source: ccache 3.5
 .\"  Language: English
 .\"
-.TH "CCACHE" "1" "09/02/2018" "ccache 3\&.4\&.3" "ccache Manual"
+.TH "CCACHE" "1" "10/15/2018" "ccache 3\&.5" "ccache Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -379,7 +379,7 @@ This setting specifies where ccache will keep its cached compiler outputs\&. It
 This setting allows you to choose the number of directory levels in the cache directory\&. The default is 2\&. The minimum is 1 and the maximum is 8\&.
 .RE
 .PP
-\fBcompiler\fR (\fBCCACHE_CC\fR)
+\fBcompiler\fR (\fBCCACHE_COMPILER\fR or (deprecated) \fBCCACHE_CC\fR)
 .RS 4
 This setting can be used to force the name of the compiler to use\&. If set to the empty string (which is the default), ccache works it out from the command line\&.
 .RE
@@ -473,6 +473,13 @@ This setting can be used to force a certain extension for the intermediate prepr
 \fBi\fR\&.
 .RE
 .PP
+\fBdebug\fR (\fBCCACHE_DEBUG\fR or \fBCCACHE_NODEBUG\fR, see Boolean values above)
+.RS 4
+If true, enable the debug mode\&. The debug mode creates per\-object debug files that are helpful when debugging unexpected cache misses\&. Note however that ccache performance will be reduced slightly\&. See
+debugging
+for more information\&. The default is false\&.
+.RE
+.PP
 \fBdirect_mode\fR (\fBCCACHE_DIRECT\fR or \fBCCACHE_NODIRECT\fR, see Boolean values above)
 .RS 4
 If true, the direct mode will be used\&. The default is true\&. See
@@ -594,6 +601,11 @@ If set, ccache will search directories in this list when looking for the real co
 that isn\(cqt a symbolic link to ccache itself\&.
 .RE
 .PP
+\fBpch_external_checksum\fR (\fBCCACHE_PCH_EXTSUM\fR or \fBCCACHE_NOPCH_EXTSUM\fR, see Boolean values above)
+.RS 4
+When this option is set, and ccache finds a precompiled header file, ccache will look for a file with the extension \(lq\&.sum\(rq added (e\&.g\&. \(lqpre\&.h\&.gch\&.sum\(rq), and if found, it will hash this file instead of the precompiled header itself to work around the performance penalty of hashing very large files\&.
+.RE
+.PP
 \fBprefix_command\fR (\fBCCACHE_PREFIX\fR)
 .RS 4
 This option adds a list of prefixes (separated by space) to the command line that ccache uses when invoking the compiler\&. See also
@@ -664,6 +676,13 @@ being present in the source\&.
 ccache normally examines a file\(cqs contents to determine whether it matches the cached version\&. With this option set, ccache will consider a file as matching its cached version if the mtimes and ctimes match\&.
 .RE
 .PP
+\fBfile_stat_matches_ctime\fR
+.RS 4
+Ignore ctimes when
+\fBfile_stat_matches\fR
+is enabled\&. This can be useful when backdating files\*(Aq mtimes in a controlled way\&.
+.RE
+.PP
 \fBinclude_file_ctime\fR
 .RS 4
 By default, ccache also will not cache a file if it includes a header whose ctime is too new\&. This option disables that check\&.
@@ -844,6 +863,8 @@ lt lt
 lt lt
 lt lt
 lt lt
+lt lt
+lt lt
 lt lt.
 T{
 .sp
@@ -1022,6 +1043,20 @@ Preprocessing the source code using the compiler\(cqs \fB\-E\fR option failed\&.
 T}
 T{
 .sp
+stats updated
+T}:T{
+.sp
+When statistics were updated the last time\&.
+T}
+T{
+.sp
+stats zeroed
+T}:T{
+.sp
+When \fBccache \-z\fR was called the last time\&.
+T}
+T{
+.sp
 unsupported code directive
 T}:T{
 .sp
@@ -1325,6 +1360,118 @@ any standard error output generated by the preprocessor
 .RE
 .sp
 Based on the hash, the cached compilation result can be looked up directly in the cache\&.
+.SH "CACHE DEBUGGING"
+.sp
+To find out what information ccache actually is hashing, you can enable the debug mode via the configuration setting \fBdebug\fR or by setting \fBCCACHE_DEBUG\fR in the environment\&. This can be useful if you are investigating why you don\(cqt get cache hits\&. Note that performance will be reduced slightly\&.
+.sp
+When the debug mode is enabled, ccache will create up to five additional files next to the object file:
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Filename
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fB<objectfile>\&.ccache\-input\-c\fR
+T}:T{
+.sp
+Binary input hashed by both the direct mode and the preprocessor mode\&.
+T}
+T{
+.sp
+\fB<objectfile>\&.ccache\-input\-d\fR
+T}:T{
+.sp
+Binary input only hashed by the direct mode\&.
+T}
+T{
+.sp
+\fB<objectfile>\&.ccache\-input\-p\fR
+T}:T{
+.sp
+Binary input only hashed by the preprocessor mode\&.
+T}
+T{
+.sp
+\fB<objectfile>\&.ccache\-input\-text\fR
+T}:T{
+.sp
+Human\-readable combined diffable text version of the three files above\&.
+T}
+T{
+.sp
+\fB<objectfile>\&.ccache\-log\fR
+T}:T{
+.sp
+Log for this object file\&.
+T}
+.TE
+.sp 1
+.sp
+In the direct mode, ccache uses the MD4 hash of the \fBccache\-input\-c\fR + \fBccache\-input\-d\fR data (where \fB+\fR means concatenation), while the \fBccache\-input\-c\fR + \fBccache\-input\-p\fR data is used in the preprocessor mode\&.
+.sp
+The \fBccache\-input\-text\fR file is a combined text version of the three binary input files\&. It has three sections (\(lqCOMMON\(rq, \(lqDIRECT MODE\(rq and \(lqPREPROCESSOR MODE\(rq), which is turn contain annotations that say what kind of data comes next\&.
+.sp
+To debug why you don\(cqt get an expected cache hit for an object file, you can do something like this:
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 1.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  1." 4.2
+.\}
+Build with debug mode enabled\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 2.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  2." 4.2
+.\}
+Save the
+\fB<objectfile>\&.ccache\-*\fR
+files\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 3.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  3." 4.2
+.\}
+Build again with debug mode enabled\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04' 4.\h'+01'\c
+.\}
+.el \{\
+.sp -1
+.IP "  4." 4.2
+.\}
+Compare
+\fB<objectfile>\&.ccache\-input\-text\fR
+for the two builds\&. This together with the
+\fB<objectfile>\&.ccache\-log\fR
+files should give you some clues about what is happening\&.
+.RE
 .SH "COMPILING IN DIFFERENT DIRECTORIES"
 .sp
 Some information included in the hash that identifies a unique compilation can contain absolute paths:
diff --git a/m4/clang.m4 b/m4/clang.m4
new file mode 100644 (file)
index 0000000..11911ce
--- /dev/null
@@ -0,0 +1,19 @@
+# _AC_LANG_COMPILER_CLANG
+# ---------------------
+# Check whether the compiler for the current language is clang.
+# Adapted from standard autoconf function: _AC_LANG_COMPILER_GNU
+#
+# Note: clang also identifies itself as a GNU compiler (gcc 4.2.1)
+# for compatibility reasons, so that cannot be used to determine
+m4_define([_AC_LANG_COMPILER_CLANG],
+[AC_CACHE_CHECK([whether we are using the clang _AC_LANG compiler],
+                [ac_cv_[]_AC_LANG_ABBREV[]_compiler_clang],
+[_AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[#ifndef __clang__
+       choke me
+#endif
+]])],
+                   [ac_compiler_clang=yes],
+                   [ac_compiler_clang=no])
+ac_cv_[]_AC_LANG_ABBREV[]_compiler_clang=$ac_compiler_clang
+])])# _AC_LANG_COMPILER_CLANG
+
index 0243e9f34507ddcee22a4759a351e5d660d6146c..05d3e493336b9f32abf8d3e21524a203880c50ad 100644 (file)
@@ -120,7 +120,7 @@ then
                 Define to the level of X/Open that your system supports)
       ;;
     *)
-      AC_DEFINE(_XOPEN_SOURCE, 600,
+      AC_DEFINE(_XOPEN_SOURCE, 700,
                 Define to the level of X/Open that your system supports)
       ;;
   esac
@@ -142,6 +142,6 @@ then
       ;;
   esac
 
-  AC_DEFINE(_POSIX_C_SOURCE, 200112L, Define to activate features from IEEE Stds 1003.1-2001)
+  AC_DEFINE(_POSIX_C_SOURCE, 200809L, Define to activate features from IEEE Stds 1003.1-2001)
 
 fi
index 66cc680181bc9e720897e5bc2c9c590b1137a931..e2400253fc71e194c997a86b4b53a44d64ba662f 100644 (file)
@@ -1,5 +1,5 @@
 // Copyright (C) 2002 Andrew Tridgell
-// Copyright (C) 2009-2016 Joel Rosdahl
+// Copyright (C) 2009-2018 Joel Rosdahl
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by the Free
@@ -168,9 +168,8 @@ args_insert(struct args *dest, int index, struct args *src, bool replace)
        }
 
        dest->argv = (char **)x_realloc(
-         dest->argv,
-         (src->argc + dest->argc + 1 - offset) *
-         sizeof(char *));
+               dest->argv,
+               (src->argc + dest->argc + 1 - offset) * sizeof(char *));
 
        // Shift arguments over.
        for (int i = dest->argc; i >= index + offset; i--) {
@@ -266,7 +265,7 @@ args_add_prefix(struct args *args, const char *s)
 void
 args_strip(struct args *args, const char *prefix)
 {
-       for (int i = 0; i < args->argc; ) {
+       for (int i = 0; i < args->argc;) {
                if (str_startswith(args->argv[i], prefix)) {
                        free(args->argv[i]);
                        memmove(&args->argv[i],
index 909a74191c6de7ece591f51fe9a3fb828ffdae67..bade8470f693791959792623480d40ecebe5930d 100644 (file)
 #else
 #include "getopt_long.h"
 #endif
+#include "hash.h"
 #include "hashtable.h"
 #include "hashtable_itr.h"
 #include "hashutil.h"
 #include "language.h"
 #include "manifest.h"
+#include "unify.h"
 
 #define STRINGIFY(x) #x
 #define TO_STRING(x) STRINGIFY(x)
 
+// Global variables used by other compilation units.
+extern struct conf *conf;
+extern char *primary_config_path;
+extern char *secondary_config_path;
+extern char *current_working_dir;
+extern char *stats_file;
+extern unsigned lock_staleness_limit;
+
 static const char VERSION_TEXT[] =
-  MYNAME " version %s\n"
-  "\n"
-  "Copyright (C) 2002-2007 Andrew Tridgell\n"
-  "Copyright (C) 2009-2018 Joel Rosdahl\n"
-  "\n"
-  "This program is free software; you can redistribute it and/or modify it under\n"
-  "the terms of the GNU General Public License as published by the Free Software\n"
-  "Foundation; either version 3 of the License, or (at your option) any later\n"
-  "version.\n";
+       MYNAME " version %s\n"
+       "\n"
+       "Copyright (C) 2002-2007 Andrew Tridgell\n"
+       "Copyright (C) 2009-2018 Joel Rosdahl\n"
+       "\n"
+       "This program is free software; you can redistribute it and/or modify it under\n"
+       "the terms of the GNU General Public License as published by the Free Software\n"
+       "Foundation; either version 3 of the License, or (at your option) any later\n"
+       "version.\n";
 
 static const char USAGE_TEXT[] =
-  "Usage:\n"
-  "    " MYNAME " [options]\n"
-  "    " MYNAME " compiler [compiler options]\n"
-  "    compiler [compiler options]          (via symbolic link)\n"
-  "\n"
-  "Options:\n"
-  "    -c, --cleanup         delete old files and recalculate size counters\n"
-  "                          (normally not needed as this is done automatically)\n"
-  "    -C, --clear           clear the cache completely (except configuration)\n"
-  "    -F, --max-files=N     set maximum number of files in cache to N (use 0 for\n"
-  "                          no limit)\n"
-  "    -M, --max-size=SIZE   set maximum size of cache to SIZE (use 0 for no\n"
-  "                          limit); available suffixes: k, M, G, T (decimal) and\n"
-  "                          Ki, Mi, Gi, Ti (binary); default suffix: G\n"
-  "    -o, --set-config=K=V  set configuration key K to value V\n"
-  "    -p, --print-config    print current configuration options\n"
-  "    -s, --show-stats      show statistics summary\n"
-  "    -z, --zero-stats      zero statistics counters\n"
-  "\n"
-  "    -h, --help            print this help text\n"
-  "    -V, --version         print version and copyright information\n"
-  "\n"
-  "See also <https://ccache.samba.org>.\n";
+       "Usage:\n"
+       "    " MYNAME " [options]\n"
+       "    " MYNAME " compiler [compiler options]\n"
+       "    compiler [compiler options]          (via symbolic link)\n"
+       "\n"
+       "Options:\n"
+       "    -c, --cleanup         delete old files and recalculate size counters\n"
+       "                          (normally not needed as this is done automatically)\n"
+       "    -C, --clear           clear the cache completely (except configuration)\n"
+       "    -F, --max-files=N     set maximum number of files in cache to N (use 0 for\n"
+       "                          no limit)\n"
+       "    -k, --get-config=K    get the value of the configuration key K\n"
+       "    -M, --max-size=SIZE   set maximum size of cache to SIZE (use 0 for no\n"
+       "                          limit); available suffixes: k, M, G, T (decimal) and\n"
+       "                          Ki, Mi, Gi, Ti (binary); default suffix: G\n"
+       "    -o, --set-config=K=V  set configuration key K to value V\n"
+       "    -p, --print-config    print current configuration options\n"
+       "    -s, --show-stats      show statistics summary\n"
+       "    -z, --zero-stats      zero statistics counters\n"
+       "\n"
+       "    -h, --help            print this help text\n"
+       "    -V, --version         print version and copyright information\n"
+       "\n"
+       "See also <https://ccache.samba.org>.\n";
 
 // Global configuration data.
 struct conf *conf = NULL;
@@ -225,6 +236,9 @@ static char *profile_dir = NULL;
 static bool profile_use = false;
 static bool profile_generate = false;
 
+// Sanitize blacklist
+static char *sanitize_blacklist = NULL;
+
 // Whether we are using a precompiled header (either via -include, #include or
 // clang's -include-pch or -include-pth).
 static bool using_precompiled_header = false;
@@ -295,6 +309,9 @@ add_prefix(struct args *args, char *prefix_command)
        args_free(prefix);
 }
 
+
+static void failed(void) ATTR_NORETURN;
+
 // Something went badly wrong - just execute the real compiler.
 static void
 failed(void)
@@ -473,6 +490,39 @@ clean_up_internal_tempdir(void)
        closedir(dir);
 }
 
+static void
+fclose_exitfn(void *context)
+{
+       fclose((FILE *)context);
+}
+
+static void
+dump_log_buffer_exitfn(void *context)
+{
+       if (!conf->debug) {
+               return;
+       }
+
+       char *path = format("%s.ccache-log", (const char *)context);
+       cc_dump_log_buffer(path);
+       free(path);
+}
+
+static void
+init_hash_debug(struct hash *hash, const char *obj_path, char type,
+                const char *section_name, FILE *debug_text_file)
+{
+       if (!conf->debug) {
+               return;
+       }
+
+       char *path = format("%s.ccache-input-%c", obj_path, type);
+       FILE *debug_binary_file = fopen(path, "wb");
+       hash_enable_debug(hash, section_name, debug_binary_file, debug_text_file);
+       free(path);
+       exitfn_add(fclose_exitfn, debug_binary_file);
+}
+
 static enum guessed_compiler
 guess_compiler(const char *path)
 {
@@ -522,7 +572,7 @@ get_path_in_cache(const char *name, const char *suffix)
        }
 
        char *result =
-         format("%s/%s%s", path, name + conf->cache_dir_levels, suffix);
+               format("%s/%s%s", path, name + conf->cache_dir_levels, suffix);
        free(path);
        return result;
 }
@@ -531,27 +581,29 @@ get_path_in_cache(const char *name, const char *suffix)
 // global included_files variable. If the include file is a PCH, cpp_hash is
 // also updated. Takes over ownership of path.
 static void
-remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
+remember_include_file(char *path, struct hash *cpp_hash, bool system)
 {
+       struct hash *fhash = NULL;
+
        size_t path_len = strlen(path);
        if (path_len >= 2 && (path[0] == '<' && path[path_len - 1] == '>')) {
                // Typically <built-in> or <command-line>.
-               goto ignore;
+               goto out;
        }
 
        if (str_eq(path, input_file)) {
                // Don't remember the input file.
-               goto ignore;
+               goto out;
        }
 
        if (system && (conf->sloppiness & SLOPPY_NO_SYSTEM_HEADERS)) {
                // Don't remember this system header.
-               goto ignore;
+               goto out;
        }
 
        if (hashtable_search(included_files, path)) {
                // Already known include file.
-               goto ignore;
+               goto out;
        }
 
 #ifdef _WIN32
@@ -559,7 +611,7 @@ remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
        DWORD attributes = GetFileAttributes(path);
        if (attributes != INVALID_FILE_ATTRIBUTES &&
            attributes & FILE_ATTRIBUTE_DIRECTORY) {
-               goto ignore;
+               goto out;
        }
 #endif
 
@@ -569,7 +621,7 @@ remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
        }
        if (S_ISDIR(st.st_mode)) {
                // Ignore directory, typically $PWD.
-               goto ignore;
+               goto out;
        }
        if (!S_ISREG(st.st_mode)) {
                // Device, pipe, socket or other strange creature.
@@ -595,7 +647,7 @@ remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
                    && (ignore[ignore_len-1] == DIR_DELIM_CH
                        || canonical[ignore_len] == DIR_DELIM_CH
                        || canonical[ignore_len] == '\0')) {
-                       goto ignore;
+                       goto out;
                }
        }
 
@@ -616,19 +668,32 @@ remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
        }
 
        // Let's hash the include file content.
-       struct mdfour fhash;
-       hash_start(&fhash);
+       fhash = hash_init();
 
        bool is_pch = is_precompiled_header(path);
        if (is_pch) {
-               if (!hash_file(&fhash, path)) {
+               bool using_pch_sum = false;
+               if (conf->pch_external_checksum) {
+                       // hash pch.sum instead of pch when it exists
+                       // to prevent hashing a very large .pch file every time
+                       char *pch_sum_path = format("%s.sum", path);
+                       if (x_stat(pch_sum_path, &st) == 0) {
+                               char *old_path = path;
+                               path = pch_sum_path;
+                               pch_sum_path = old_path;
+                               using_pch_sum = true;
+                               cc_log("Using pch.sum file %s", path);
+                       }
+                       free(pch_sum_path);
+               }
+
+               if (!hash_file(fhash, path)) {
                        goto failure;
                }
-               struct file_hash pch_hash;
-               hash_result_as_bytes(&fhash, pch_hash.hash);
-               pch_hash.size = fhash.totalN;
-               hash_delimiter(cpp_hash, "pch_hash");
-               hash_buffer(cpp_hash, pch_hash.hash, sizeof(pch_hash.hash));
+               hash_delimiter(cpp_hash, using_pch_sum ? "pch_sum_hash" : "pch_hash");
+               char *pch_hash_result = hash_result(fhash);
+               hash_string(cpp_hash, pch_hash_result);
+               free(pch_hash_result);
        }
 
        if (conf->direct_mode) {
@@ -644,7 +709,7 @@ remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
                                size = 0;
                        }
 
-                       int result = hash_source_code_string(conf, &fhash, source, size, path);
+                       int result = hash_source_code_string(conf, fhash, source, size, path);
                        free(source);
                        if (result & HASH_SOURCE_CODE_ERROR
                            || result & HASH_SOURCE_CODE_FOUND_TIME) {
@@ -653,14 +718,13 @@ remember_include_file(char *path, struct mdfour *cpp_hash, bool system)
                }
 
                struct file_hash *h = x_malloc(sizeof(*h));
-               hash_result_as_bytes(&fhash, h->hash);
-               h->size = fhash.totalN;
+               hash_result_as_bytes(fhash, h->hash);
+               h->size = hash_input_size(fhash);
                hashtable_insert(included_files, path, h);
-       } else {
-               free(path);
+               path = NULL; // Ownership transferred to included_files.
        }
 
-       return;
+       goto out;
 
 failure:
        if (conf->direct_mode) {
@@ -668,7 +732,8 @@ failure:
                conf->direct_mode = false;
        }
        // Fall through.
-ignore:
+out:
+       hash_free(fhash);
        free(path);
 }
 
@@ -736,7 +801,7 @@ make_relative_path(char *path)
 // - Stores the paths and hashes of included files in the global variable
 //   included_files.
 static bool
-process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
+process_preprocessed_file(struct hash *hash, const char *path, bool pump)
 {
        char *data;
        size_t size;
@@ -763,6 +828,8 @@ process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
                included_files = create_hashtable(1000, hash_from_string, strings_equal);
        }
 
+       char *cwd = gnu_getcwd();
+
        // Bytes between p and q are pending to be hashed.
        char *p = data;
        char *q = data;
@@ -806,7 +873,7 @@ process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
                                if (str_startswith(q, "# 31 \"<command-line>\"\n")) {
                                        // Bogus extra line with #31, after the regular #1: Ignore the whole
                                        // line, and continue parsing.
-                                       hash_buffer(hash, p, q - p);
+                                       hash_string_buffer(hash, p, q - p);
                                        while (q < end && *q != '\n') {
                                                q++;
                                        }
@@ -816,7 +883,7 @@ process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
                                } else if (str_startswith(q, "# 32 \"<command-line>\" 2\n")) {
                                        // Bogus wrong line with #32, instead of regular #1: Replace the line
                                        // number with the usual one.
-                                       hash_buffer(hash, p, q - p);
+                                       hash_string_buffer(hash, p, q - p);
                                        q += 1;
                                        q[0] = '#';
                                        q[1] = ' ';
@@ -836,10 +903,11 @@ process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
                        if (q >= end) {
                                cc_log("Failed to parse included file path");
                                free(data);
+                               free(cwd);
                                return false;
                        }
                        // q points to the beginning of an include file path
-                       hash_buffer(hash, p, q - p);
+                       hash_string_buffer(hash, p, q - p);
                        p = q;
                        while (q < end && *q != '"') {
                                q++;
@@ -862,7 +930,6 @@ process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
 
                        bool should_hash_inc_path = true;
                        if (!conf->hash_dir) {
-                               char *cwd = gnu_getcwd();
                                if (str_startswith(inc_path, cwd) && str_endswith(inc_path, "//")) {
                                        // When compiling with -g or similar, GCC adds the absolute path to
                                        // CWD like this:
@@ -873,10 +940,9 @@ process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
                                        // hash it. See also how debug_prefix_map is handled.
                                        should_hash_inc_path = false;
                                }
-                               free(cwd);
                        }
                        if (should_hash_inc_path) {
-                               hash_string(hash, inc_path);
+                               hash_string_buffer(hash, inc_path, strlen(inc_path));
                        }
 
                        remember_include_file(inc_path, hash, system);
@@ -908,16 +974,17 @@ process_preprocessed_file(struct mdfour *hash, const char *path, bool pump)
                }
        }
 
-       hash_buffer(hash, p, (end - p));
+       hash_string_buffer(hash, p, (end - p));
        free(data);
+       free(cwd);
 
        // Explicitly check the .gch/.pch/.pth file, Clang does not include any
        // mention of it in the preprocessed output.
        if (included_pch_file) {
-               char *path = x_strdup(included_pch_file);
-               path = make_relative_path(path);
-               hash_string(hash, path);
-               remember_include_file(path, hash, false);
+               char *pch_path = x_strdup(included_pch_file);
+               pch_path = make_relative_path(pch_path);
+               hash_string(hash, pch_path);
+               remember_include_file(pch_path, hash, false);
        }
 
        return true;
@@ -1022,8 +1089,7 @@ do_copy_or_move_file_to_cache(const char *source, const char *dest, bool copy)
                if (do_link) {
                        x_unlink(dest);
                        int ret = link(source, dest);
-                       if (ret == 0) {
-                       } else {
+                       if (ret != 0) {
                                cc_log("Failed to link %s to %s: %s", source, dest, strerror(errno));
                                cc_log("Falling back to copying");
                                do_link = false;
@@ -1055,8 +1121,8 @@ do_copy_or_move_file_to_cache(const char *source, const char *dest, bool copy)
                failed();
        }
        stats_update_size(
-         file_size(&st) - (orig_dest_existed ? file_size(&orig_dest_st) : 0),
-         orig_dest_existed ? 0 : 1);
+               file_size(&st) - (orig_dest_existed ? file_size(&orig_dest_st) : 0),
+               orig_dest_existed ? 0 : 1);
 }
 
 // Copy a file into the cache.
@@ -1138,7 +1204,8 @@ send_cached_stderr(void)
 }
 
 // Create or update the manifest file.
-void update_manifest_file(void)
+static void
+update_manifest_file(void)
 {
        if (!conf->direct_mode
            || !included_files
@@ -1194,7 +1261,7 @@ to_cache(struct args *args)
 
        cc_log("Running real compiler");
        int status =
-         execute(args->argv, tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
+               execute(args->argv, tmp_stdout_fd, tmp_stderr_fd, &compiler_pid);
        args_pop(args, 3);
 
        struct stat st;
@@ -1240,7 +1307,7 @@ to_cache(struct args *args)
                }
 
                int fd_result =
-                 open(tmp_stderr, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+                       open(tmp_stderr, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
                if (fd_result == -1) {
                        cc_log("Failed opening %s: %s", tmp_stderr, strerror(errno));
                        failed();
@@ -1351,7 +1418,7 @@ to_cache(struct args *args)
 // Find the object file name by running the compiler in preprocessor mode.
 // Returns the hash as a heap-allocated hex string.
 static struct file_hash *
-get_object_name_from_cpp(struct args *args, struct mdfour *hash)
+get_object_name_from_cpp(struct args *args, struct hash *hash)
 {
        time_of_compilation = time(NULL);
 
@@ -1454,7 +1521,7 @@ get_object_name_from_cpp(struct args *args, struct mdfour *hash)
 
        struct file_hash *result = x_malloc(sizeof(*result));
        hash_result_as_bytes(hash, result->hash);
-       result->size = hash->totalN;
+       result->size = hash_input_size(hash);
        return result;
 }
 
@@ -1478,7 +1545,7 @@ update_cached_result_globals(struct file_hash *hash)
 // Hash mtime or content of a file, or the output of a command, according to
 // the CCACHE_COMPILERCHECK setting.
 static void
-hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
+hash_compiler(struct hash *hash, struct stat *st, const char *path,
               bool allow_command)
 {
        if (str_eq(conf->compiler_check, "none")) {
@@ -1494,8 +1561,9 @@ hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
                hash_delimiter(hash, "cc_content");
                hash_file(hash, path);
        } else { // command string
-               if (!hash_multicommand_output(
-                     hash, conf->compiler_check, orig_args->argv[0])) {
+               bool ok = hash_multicommand_output(
+                       hash, conf->compiler_check, orig_args->argv[0]);
+               if (!ok) {
                        fatal("Failure running compiler check command: %s", conf->compiler_check);
                }
        }
@@ -1507,7 +1575,7 @@ hash_compiler(struct mdfour *hash, struct stat *st, const char *path,
 // with -ccbin/--compiler-bindir. If they are NULL, the compilers are looked up
 // in PATH instead.
 static void
-hash_nvcc_host_compiler(struct mdfour *hash, struct stat *ccbin_st,
+hash_nvcc_host_compiler(struct hash *hash, struct stat *ccbin_st,
                         const char *ccbin)
 {
        // From <http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html>:
@@ -1556,7 +1624,7 @@ hash_nvcc_host_compiler(struct mdfour *hash, struct stat *ccbin_st,
 // Update a hash sum with information common for the direct and preprocessor
 // modes.
 static void
-calculate_common_hash(struct args *args, struct mdfour *hash)
+calculate_common_hash(struct args *args, struct hash *hash)
 {
        hash_string(hash, HASH_PREFIX);
 
@@ -1587,9 +1655,9 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
        // Also hash the compiler name as some compilers use hard links and behave
        // differently depending on the real name.
        hash_delimiter(hash, "cc_name");
-       char *p = basename(args->argv[0]);
-       hash_string(hash, p);
-       free(p);
+       char *base = basename(args->argv[0]);
+       hash_string(hash, base);
+       free(base);
 
        // Possibly hash the current working directory.
        if (generating_debuginfo && conf->hash_dir) {
@@ -1630,7 +1698,7 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
                }
                if (dir) {
                        char *base_name = basename(output_obj);
-                       p = remove_extension(base_name);
+                       char *p = remove_extension(base_name);
                        free(base_name);
                        char *gcda_path = format("%s/%s.gcda", dir, p);
                        cc_log("Hashing coverage path %s", gcda_path);
@@ -1641,6 +1709,16 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
                }
        }
 
+       // Possibly hash the sanitize blacklist file path.
+       if (sanitize_blacklist) {
+               cc_log("Hashing sanitize blacklist %s", sanitize_blacklist);
+               hash_delimiter(hash, "sanitizeblacklist");
+               if (!hash_file(hash, sanitize_blacklist)) {
+                       stats_update(STATS_BADEXTRAFILE);
+                       failed();
+               }
+       }
+
        if (!str_eq(conf->extra_files_to_hash, "")) {
                char *p = x_strdup(conf->extra_files_to_hash);
                char *q = p;
@@ -1672,7 +1750,7 @@ calculate_common_hash(struct args *args, struct mdfour *hash)
 // modes and calculate the object hash. Returns the object hash on success,
 // otherwise NULL. Caller frees.
 static struct file_hash *
-calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
+calculate_object_hash(struct args *args, struct hash *hash, int direct_mode)
 {
        bool found_ccbin = false;
 
@@ -1683,7 +1761,8 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
 
        // clang will emit warnings for unused linker flags, so we shouldn't skip
        // those arguments.
-       int is_clang = guessed_compiler == GUESSED_CLANG;
+       int is_clang =
+               guessed_compiler == GUESSED_CLANG || guessed_compiler == GUESSED_UNKNOWN;
 
        // First the arguments.
        for (int i = 1; i < args->argc; i++) {
@@ -1731,16 +1810,17 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
                        if (str_startswith(args->argv[i], "-Wp,")) {
                                if (str_startswith(args->argv[i], "-Wp,-MD,")
                                    && !strchr(args->argv[i] + 8, ',')) {
-                                       hash_string_length(hash, args->argv[i], 8);
+                                       hash_string_buffer(hash, args->argv[i], 8);
                                        continue;
                                } else if (str_startswith(args->argv[i], "-Wp,-MMD,")
                                           && !strchr(args->argv[i] + 9, ',')) {
-                                       hash_string_length(hash, args->argv[i], 9);
+                                       hash_string_buffer(hash, args->argv[i], 9);
                                        continue;
                                }
                        } else if (str_startswith(args->argv[i], "-MF")) {
                                // In either case, hash the "-MF" part.
-                               hash_string_length(hash, args->argv[i], 3);
+                               hash_delimiter(hash, "arg");
+                               hash_string_buffer(hash, args->argv[i], 3);
 
                                bool separate_argument = (strlen(args->argv[i]) == 3);
                                if (separate_argument) {
@@ -1787,8 +1867,8 @@ calculate_object_hash(struct args *args, struct mdfour *hash, int direct_mode)
 
                if ((str_eq(args->argv[i], "-ccbin")
                     || str_eq(args->argv[i], "--compiler-bindir"))
-                    && i + 1 < args->argc
-                    && x_stat(args->argv[i+1], &st) == 0) {
+                   && i + 1 < args->argc
+                   && x_stat(args->argv[i+1], &st) == 0) {
                        found_ccbin = true;
                        hash_delimiter(hash, "ccbin");
                        hash_nvcc_host_compiler(hash, &st, args->argv[i+1]);
@@ -1941,7 +2021,7 @@ from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
        //
        //     file 'foo.h' has been modified since the precompiled header 'foo.pch'
        //     was built
-       if (guessed_compiler == GUESSED_CLANG
+       if ((guessed_compiler == GUESSED_CLANG || guessed_compiler == GUESSED_UNKNOWN)
            && output_is_precompiled_header
            && mode == FROMCACHE_CPP_MODE) {
                cc_log("Not considering cached precompiled header in preprocessor mode");
@@ -1963,7 +2043,7 @@ from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest)
 
        // (If mode != FROMCACHE_DIRECT_MODE, the dependency file is created by gcc.)
        bool produce_dep_file =
-         generating_dependencies && mode == FROMCACHE_DIRECT_MODE;
+               generating_dependencies && mode == FROMCACHE_DIRECT_MODE;
 
        // Get result from cache.
        if (!str_eq(output_obj, "/dev/null")) {
@@ -2371,8 +2451,8 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                }
                if (str_startswith(argv[i], "-fdebug-prefix-map=")) {
                        debug_prefix_maps = x_realloc(
-                         debug_prefix_maps,
-                         (debug_prefix_maps_len + 1) * sizeof(char *));
+                               debug_prefix_maps,
+                               (debug_prefix_maps_len + 1) * sizeof(char *));
                        debug_prefix_maps[debug_prefix_maps_len++] = x_strdup(argv[i] + 19);
                        args_add(stripped_args, argv[i]);
                        continue;
@@ -2488,6 +2568,11 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                        args_add(stripped_args, argv[i]);
                        continue;
                }
+               if (str_startswith(argv[i], "-fsanitize-blacklist=")) {
+                       sanitize_blacklist = x_strdup(argv[i] + 21);
+                       args_add(stripped_args, argv[i]);
+                       continue;
+               }
                if (str_startswith(argv[i], "--sysroot=")) {
                        char *relpath = make_relative_path(x_strdup(argv[i] + 10));
                        char *option = format("--sysroot=%s", relpath);
@@ -2863,7 +2948,7 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
        }
 
        output_is_precompiled_header =
-         actual_language && strstr(actual_language, "-header");
+               actual_language && strstr(actual_language, "-header");
 
        if (output_is_precompiled_header
            && !(conf->sloppiness & SLOPPY_PCH_DEFINES)) {
@@ -3085,7 +3170,7 @@ out:
 }
 
 static void
-create_initial_config_file(struct conf *conf, const char *path)
+create_initial_config_file(const char *path)
 {
        if (create_parent_dirs(path) != 0) {
                return;
@@ -3176,7 +3261,7 @@ initialize(void)
        }
 
        if (should_create_initial_config) {
-               create_initial_config_file(conf, primary_config_path);
+               create_initial_config_file(primary_config_path);
        }
 
        exitfn_init();
@@ -3206,6 +3291,7 @@ cc_reset(void)
        free(debug_prefix_maps); debug_prefix_maps = NULL;
        debug_prefix_maps_len = 0;
        free(profile_dir); profile_dir = NULL;
+       free(sanitize_blacklist); sanitize_blacklist = NULL;
        free(included_pch_file); included_pch_file = NULL;
        args_free(orig_args); orig_args = NULL;
        free(input_file); input_file = NULL;
@@ -3277,6 +3363,8 @@ configuration_logger(const char *descr, const char *origin, void *context)
        cc_bulklog("Config: (%s) %s", origin, descr);
 }
 
+static void ccache(int argc, char *argv[]) ATTR_NORETURN;
+
 // The main ccache driver function.
 static void
 ccache(int argc, char *argv[])
@@ -3294,7 +3382,7 @@ ccache(int argc, char *argv[])
                clean_up_internal_tempdir();
        }
 
-       if (!str_eq(conf->log_file, "")) {
+       if (!str_eq(conf->log_file, "") || conf->debug) {
                conf_print_items(conf, configuration_logger, NULL);
        }
 
@@ -3340,18 +3428,33 @@ ccache(int argc, char *argv[])
 
        cc_log("Object file: %s", output_obj);
 
-       struct mdfour common_hash;
-       hash_start(&common_hash);
-       calculate_common_hash(preprocessor_args, &common_hash);
+       // Need to dump log buffer as the last exit function to not lose any logs.
+       exitfn_add_last(dump_log_buffer_exitfn, output_obj);
+
+       FILE *debug_text_file = NULL;
+       if (conf->debug) {
+               char *path = format("%s.ccache-input-text", output_obj);
+               debug_text_file = fopen(path, "w");
+               free(path);
+               exitfn_add(fclose_exitfn, debug_text_file);
+       }
+
+       struct hash *common_hash = hash_init();
+       init_hash_debug(common_hash, output_obj, 'c', "COMMON", debug_text_file);
+
+       calculate_common_hash(preprocessor_args, common_hash);
 
        // Try to find the hash using the manifest.
-       struct mdfour direct_hash = common_hash;
+       struct hash *direct_hash = hash_copy(common_hash);
+       init_hash_debug(
+               direct_hash, output_obj, 'd', "DIRECT MODE", debug_text_file);
+
        bool put_object_in_manifest = false;
        struct file_hash *object_hash = NULL;
        struct file_hash *object_hash_from_manifest = NULL;
        if (conf->direct_mode) {
                cc_log("Trying direct lookup");
-               object_hash = calculate_object_hash(preprocessor_args, &direct_hash, 1);
+               object_hash = calculate_object_hash(preprocessor_args, direct_hash, 1);
                if (object_hash) {
                        update_cached_result_globals(object_hash);
 
@@ -3375,8 +3478,11 @@ ccache(int argc, char *argv[])
        }
 
        // Find the hash using the preprocessed output. Also updates included_files.
-       struct mdfour cpp_hash = common_hash;
-       object_hash = calculate_object_hash(preprocessor_args, &cpp_hash, 0);
+       struct hash *cpp_hash = hash_copy(common_hash);
+       init_hash_debug(
+               cpp_hash, output_obj, 'p', "PREPROCESSOR MODE", debug_text_file);
+
+       object_hash = calculate_object_hash(preprocessor_args, cpp_hash, 0);
        if (!object_hash) {
                fatal("internal error: object hash from cpp returned NULL");
        }
@@ -3432,17 +3538,20 @@ static int
 ccache_main_options(int argc, char *argv[])
 {
        enum longopts {
-               DUMP_MANIFEST
+               DUMP_MANIFEST,
+               HASH_FILE
        };
        static const struct option options[] = {
                {"cleanup",       no_argument,       0, 'c'},
                {"clear",         no_argument,       0, 'C'},
                {"dump-manifest", required_argument, 0, DUMP_MANIFEST},
+               {"get-config",    required_argument, 0, 'k'},
+               {"hash-file",     required_argument, 0, HASH_FILE},
                {"help",          no_argument,       0, 'h'},
                {"max-files",     required_argument, 0, 'F'},
                {"max-size",      required_argument, 0, 'M'},
-               {"set-config",    required_argument, 0, 'o'},
                {"print-config",  no_argument,       0, 'p'},
+               {"set-config",    required_argument, 0, 'o'},
                {"show-stats",    no_argument,       0, 's'},
                {"version",       no_argument,       0, 'V'},
                {"zero-stats",    no_argument,       0, 'z'},
@@ -3450,12 +3559,29 @@ ccache_main_options(int argc, char *argv[])
        };
 
        int c;
-       while ((c = getopt_long(argc, argv, "cChF:M:o:psVz", options, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "cCk:hF:M:po:sVz", options, NULL))
+              != -1) {
                switch (c) {
                case DUMP_MANIFEST:
                        manifest_dump(optarg, stdout);
                        break;
 
+               case HASH_FILE:
+               {
+                       initialize();
+                       struct hash *hash = hash_init();
+                       if (str_eq(optarg, "-")) {
+                               hash_fd(hash, STDIN_FILENO);
+                       } else {
+                               hash_file(hash, optarg);
+                       }
+                       char *result = hash_result(hash);
+                       puts(result);
+                       free(result);
+                       hash_free(hash);
+                       break;
+               }
+
                case 'c': // --cleanup
                        initialize();
                        clean_up_all(conf);
@@ -3472,6 +3598,16 @@ ccache_main_options(int argc, char *argv[])
                        fputs(USAGE_TEXT, stdout);
                        x_exit(0);
 
+               case 'k': // --get-config
+               {
+                       initialize();
+                       char *errmsg;
+                       if (!conf_print_value(conf, optarg, stdout, &errmsg)) {
+                               fatal("%s", errmsg);
+                       }
+               }
+               break;
+
                case 'F': // --max-files
                {
                        initialize();
@@ -3537,7 +3673,7 @@ ccache_main_options(int argc, char *argv[])
 
                case 's': // --show-stats
                        initialize();
-                       stats_summary(conf);
+                       stats_summary();
                        break;
 
                case 'V': // --version
@@ -3547,7 +3683,7 @@ ccache_main_options(int argc, char *argv[])
                case 'z': // --zero-stats
                        initialize();
                        stats_zero();
-                       printf("Statistics cleared\n");
+                       printf("Statistics zeroed\n");
                        break;
 
                default:
@@ -3559,6 +3695,8 @@ ccache_main_options(int argc, char *argv[])
        return 0;
 }
 
+int ccache_main(int argc, char *argv[]);
+
 int
 ccache_main(int argc, char *argv[])
 {
@@ -3578,5 +3716,4 @@ ccache_main(int argc, char *argv[])
        free(program_name);
 
        ccache(argc, argv);
-       return 1;
 }
index 973d42dd3c7af9cda1fb245117f9533430e738d2..091662121ef1eedf726fdc47fd6dc00bc93b9e82 100644 (file)
@@ -1,14 +1,30 @@
+// Copyright (C) 2002-2007 Andrew Tridgell
+// Copyright (C) 2009-2018 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
 #ifndef CCACHE_H
 #define CCACHE_H
 
 #include "system.h"
-#include "mdfour.h"
 #include "conf.h"
 #include "counters.h"
 
 #ifdef __GNUC__
 #define ATTR_FORMAT(x, y, z) __attribute__((format (x, y, z)))
-#define ATTR_NORETURN __attribute__((noreturn));
+#define ATTR_NORETURN __attribute__((noreturn))
 #else
 #define ATTR_FORMAT(x, y, z)
 #define ATTR_NORETURN
@@ -79,6 +95,9 @@ extern enum guessed_compiler guessed_compiler;
 // Allow us to not include any system headers in the manifest include files,
 // similar to -MM versus -M for dependencies.
 #define SLOPPY_NO_SYSTEM_HEADERS 64
+// Allow us to ignore ctimes when comparing file stats, so we can fake mtimes
+// if we want to (it is much harder to fake ctimes, requires changing clock)
+#define SLOPPY_FILE_STAT_MATCHES_CTIME 128
 
 #define str_eq(s1, s2) (strcmp((s1), (s2)) == 0)
 #define str_startswith(s, prefix) \
@@ -115,27 +134,13 @@ void args_remove_first(struct args *args);
 char *args_to_string(struct args *args);
 bool args_equal(struct args *args1, struct args *args2);
 
-// ----------------------------------------------------------------------------
-// hash.c
-
-void hash_start(struct mdfour *md);
-void hash_buffer(struct mdfour *md, const void *s, size_t len);
-char *hash_result(struct mdfour *md);
-void hash_result_as_bytes(struct mdfour *md, unsigned char *out);
-bool hash_equal(struct mdfour *md1, struct mdfour *md2);
-void hash_delimiter(struct mdfour *md, const char *type);
-void hash_string(struct mdfour *md, const char *s);
-void hash_string_length(struct mdfour *md, const char *s, int length);
-void hash_int(struct mdfour *md, int x);
-bool hash_fd(struct mdfour *md, int fd);
-bool hash_file(struct mdfour *md, const char *fname);
-
 // ----------------------------------------------------------------------------
 // util.c
 
 void cc_log(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
 void cc_bulklog(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
 void cc_log_argv(const char *prefix, char **argv);
+bool cc_dump_log_buffer(const char *path);
 void fatal(const char *format, ...) ATTR_FORMAT(printf, 1, 2) ATTR_NORETURN;
 void warn(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
 
@@ -207,7 +212,7 @@ void stats_update(enum stats stat);
 void stats_flush(void);
 unsigned stats_get_pending(enum stats stat);
 void stats_zero(void);
-void stats_summary(struct conf *conf);
+void stats_summary(void);
 void stats_update_size(int64_t size, int files);
 void stats_get_obsolete_limits(const char *dir, unsigned *maxfiles,
                                uint64_t *maxsize);
@@ -217,17 +222,13 @@ void stats_timestamp(time_t time, struct counters *counters);
 void stats_read(const char *path, struct counters *counters);
 void stats_write(const char *path, struct counters *counters);
 
-// ----------------------------------------------------------------------------
-// unify.c
-
-int unify_hash(struct mdfour *hash, const char *fname, bool print);
-
 // ----------------------------------------------------------------------------
 // exitfn.c
 
 void exitfn_init(void);
 void exitfn_add_nullary(void (*function)(void));
 void exitfn_add(void (*function)(void *), void *context);
+void exitfn_add_last(void (*function)(void *), void *context);
 void exitfn_call(void);
 
 // ----------------------------------------------------------------------------
@@ -243,6 +244,7 @@ void wipe_all(struct conf *conf);
 int execute(char **argv, int fd_out, int fd_err, pid_t *pid);
 char *find_executable(const char *name, const char *exclude_name);
 void print_command(FILE *fp, char **argv);
+char *format_command(char **argv);
 
 // ----------------------------------------------------------------------------
 // lockfile.c
@@ -264,7 +266,7 @@ bool is_precompiled_header(const char *path);
 
 // ----------------------------------------------------------------------------
 
-#if HAVE_COMPAR_FN_T
+#ifdef HAVE_COMPAR_FN_T
 #define COMPAR_FN_T __compar_fn_t
 #else
 typedef int (*COMPAR_FN_T)(const void *, const void *);
@@ -275,11 +277,6 @@ typedef int (*COMPAR_FN_T)(const void *, const void *);
 #define O_BINARY 0
 #endif
 
-// mkstemp() on some versions of cygwin don't handle binary files, so override.
-#ifdef __CYGWIN__
-#undef HAVE_MKSTEMP
-#endif
-
 #ifdef _WIN32
 char *win32argvtos(char *prefix, char **argv);
 char *win32getshell(char *path);
index 969b8d2bc80ba147d575be57291a15f46f67cc70..0b66cafcda089649bdfbf944b0d91665c015081b 100644 (file)
@@ -164,8 +164,10 @@ clean_up_dir(struct conf *conf, const char *dir, double limit_multiple)
        // When "max files" or "max cache size" is reached, one of the 16 cache
        // subdirectories is cleaned up. When doing so, files are deleted (in LRU
        // order) until the levels are below limit_multiple.
-       cache_size_threshold = round(conf->max_size * limit_multiple / 16);
-       files_in_cache_threshold = round(conf->max_files * limit_multiple / 16);
+       double cache_size_float = round(conf->max_size * limit_multiple / 16);
+       cache_size_threshold = (uint64_t)cache_size_float;
+       double files_in_cache_float = round(conf->max_files * limit_multiple / 16);
+       files_in_cache_threshold = (size_t)files_in_cache_float;
 
        num_files = 0;
        cache_size = 0;
@@ -237,7 +239,7 @@ static void wipe_fn(const char *fname, struct stat *st)
 }
 
 // Wipe one cache subdirectory.
-void
+static void
 wipe_dir(const char *dir)
 {
        cc_log("Clearing out cache directory %s", dir);
index 63351acb0a6798062423262d24608bb4fa6cc25d..cb67d7a73f4ff141a1ea844761e0a484f539305a 100644 (file)
@@ -35,8 +35,8 @@ static const struct compopt compopts[] = {
        {"--output-directory", AFFECTS_CPP | TAKES_ARG}, // nvcc
        {"--param",         TAKES_ARG},
        {"--save-temps",    TOO_HARD},
-       {"--save-temps=cwd",TOO_HARD},
-       {"--save-temps=obj",TOO_HARD},
+       {"--save-temps=cwd", TOO_HARD},
+       {"--save-temps=obj", TOO_HARD},
        {"--serialize-diagnostics", TAKES_ARG | TAKES_PATH},
        {"-A",              TAKES_ARG},
        {"-B",              TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH},
@@ -142,6 +142,9 @@ compopt_short(bool (*fn)(const char *), const char *option)
        return retval;
 }
 
+// Used by unittest/test_compopt.c.
+bool compopt_verify_sortedness(void);
+
 // For test purposes.
 bool
 compopt_verify_sortedness(void)
index 4fbc7d0b38ceba66aced21bd47a020028b8d6474..404d2d7f7a5871cda37807335e03fde5a2838619 100644 (file)
@@ -19,6 +19,7 @@
 
 typedef bool (*conf_item_parser)(const char *str, void *result, char **errmsg);
 typedef bool (*conf_item_verifier)(void *value, char **errmsg);
+typedef const char *(*conf_item_formatter)(void *value);
 
 struct conf_item {
        const char *name;
@@ -26,6 +27,7 @@ struct conf_item {
        conf_item_parser parser;
        size_t offset;
        conf_item_verifier verifier;
+       conf_item_formatter formatter;
 };
 
 struct env_to_conf_item {
@@ -50,6 +52,19 @@ parse_bool(const char *str, void *result, char **errmsg)
        }
 }
 
+static const char *
+bool_to_string(bool value)
+{
+       return value ? "true" : "false";
+}
+
+static const char *
+format_bool(void *value)
+{
+       bool *b = (bool *)value;
+       return x_strdup(bool_to_string(*b));
+}
+
 static bool
 parse_env_string(const char *str, void *result, char **errmsg)
 {
@@ -59,6 +74,19 @@ parse_env_string(const char *str, void *result, char **errmsg)
        return *value != NULL;
 }
 
+static const char *
+format_string(void *value)
+{
+       char **str = (char **)value;
+       return x_strdup(*str);
+}
+
+static const char *
+format_env_string(void *value)
+{
+       return format_string(value);
+}
+
 static bool
 parse_float(const char *str, void *result, char **errmsg)
 {
@@ -75,6 +103,13 @@ parse_float(const char *str, void *result, char **errmsg)
        }
 }
 
+static const char *
+format_float(void *value)
+{
+       float *x = (float *)value;
+       return format("%.1f", *x);
+}
+
 static bool
 parse_size(const char *str, void *result, char **errmsg)
 {
@@ -89,6 +124,13 @@ parse_size(const char *str, void *result, char **errmsg)
        }
 }
 
+static const char *
+format_size(void *value)
+{
+       uint64_t *size = (uint64_t *)value;
+       return format_parsable_size_with_suffix(*size);
+}
+
 static bool
 parse_sloppiness(const char *str, void *result, char **errmsg)
 {
@@ -106,6 +148,8 @@ parse_sloppiness(const char *str, void *result, char **errmsg)
                        *value |= SLOPPY_FILE_MACRO;
                } else if (str_eq(word, "file_stat_matches")) {
                        *value |= SLOPPY_FILE_STAT_MATCHES;
+               } else if (str_eq(word, "file_stat_matches_ctime")) {
+                       *value |= SLOPPY_FILE_STAT_MATCHES_CTIME;
                } else if (str_eq(word, "include_file_ctime")) {
                        *value |= SLOPPY_INCLUDE_FILE_CTIME;
                } else if (str_eq(word, "include_file_mtime")) {
@@ -127,6 +171,42 @@ parse_sloppiness(const char *str, void *result, char **errmsg)
        return true;
 }
 
+static const char *
+format_sloppiness(void *value)
+{
+       unsigned *sloppiness = (unsigned *)value;
+       char *s = x_strdup("");
+       if (*sloppiness & SLOPPY_FILE_MACRO) {
+               reformat(&s, "%sfile_macro, ", s);
+       }
+       if (*sloppiness & SLOPPY_INCLUDE_FILE_MTIME) {
+               reformat(&s, "%sinclude_file_mtime, ", s);
+       }
+       if (*sloppiness & SLOPPY_INCLUDE_FILE_CTIME) {
+               reformat(&s, "%sinclude_file_ctime, ", s);
+       }
+       if (*sloppiness & SLOPPY_TIME_MACROS) {
+               reformat(&s, "%stime_macros, ", s);
+       }
+       if (*sloppiness & SLOPPY_PCH_DEFINES) {
+               reformat(&s, "%spch_defines, ", s);
+       }
+       if (*sloppiness & SLOPPY_FILE_STAT_MATCHES) {
+               reformat(&s, "%sfile_stat_matches, ", s);
+       }
+       if (*sloppiness & SLOPPY_FILE_STAT_MATCHES_CTIME) {
+               reformat(&s, "%sfile_stat_matches_ctime, ", s);
+       }
+       if (*sloppiness & SLOPPY_NO_SYSTEM_HEADERS) {
+               reformat(&s, "%sno_system_headers, ", s);
+       }
+       if (*sloppiness) {
+               // Strip last ", ".
+               s[strlen(s) - 2] = '\0';
+       }
+       return s;
+}
+
 static bool
 parse_string(const char *str, void *result, char **errmsg)
 {
@@ -158,6 +238,17 @@ parse_umask(const char *str, void *result, char **errmsg)
        }
 }
 
+static const char *
+format_umask(void *value)
+{
+       unsigned *umask = (unsigned *)value;
+       if (*umask == UINT_MAX) {
+               return x_strdup("");
+       } else {
+               return format("%03o", *umask);
+       }
+}
+
 static bool
 parse_unsigned(const char *str, void *result, char **errmsg)
 {
@@ -175,9 +266,10 @@ parse_unsigned(const char *str, void *result, char **errmsg)
 }
 
 static const char *
-bool_to_string(bool value)
+format_unsigned(void *value)
 {
-       return value ? "true" : "false";
+       unsigned *i = (unsigned *)value;
+       return format("%u", *i);
 }
 
 static bool
@@ -210,9 +302,10 @@ verify_dir_levels(void *value, char **errmsg)
 }
 
 #define ITEM(name, type) \
-  parse_ ## type, offsetof(struct conf, name), NULL
+       parse_ ## type, offsetof(struct conf, name), NULL, format_ ## type
 #define ITEM_V(name, type, verification) \
-  parse_ ## type, offsetof(struct conf, name), verify_ ## verification
+       parse_ ## type, offsetof(struct conf, name), \
+       verify_ ## verification, format_ ## type
 
 #include "confitems_lookup.c"
 #include "envtoconfitems_lookup.c"
@@ -253,8 +346,8 @@ handle_conf_setting(struct conf *conf, const char *key, const char *value,
                        fatal("invalid boolean environment variable value \"%s\"", value);
                }
 
-               bool *value = (bool *)((char *)conf + item->offset);
-               *value = !negate_boolean;
+               bool *boolvalue = (bool *)((char *)conf + item->offset);
+               *boolvalue = !negate_boolean;
                goto out;
        }
 
@@ -328,6 +421,7 @@ conf_create(void)
        conf->compression = false;
        conf->compression_level = 6;
        conf->cpp_extension = x_strdup("");
+       conf->debug = false;
        conf->direct_mode = true;
        conf->disable = false;
        conf->extra_files_to_hash = x_strdup("");
@@ -340,6 +434,7 @@ conf_create(void)
        conf->max_files = 0;
        conf->max_size = (uint64_t)5 * 1000 * 1000 * 1000;
        conf->path = x_strdup("");
+       conf->pch_external_checksum = false;
        conf->prefix_command = x_strdup("");
        conf->prefix_command_cpp = x_strdup("");
        conf->read_only = false;
@@ -376,7 +471,7 @@ conf_free(struct conf *conf)
        free(conf->prefix_command);
        free(conf->prefix_command_cpp);
        free(conf->temporary_dir);
-       free(conf->item_origins);
+       free((void *)conf->item_origins); // Workaround for MSVC warning
        free(conf);
 }
 
@@ -461,9 +556,10 @@ conf_update_from_environment(struct conf *conf, char **errmsg)
                }
 
                char *errmsg2;
-               if (!handle_conf_setting(
-                     conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
-                     "environment")) {
+               bool ok = handle_conf_setting(
+                       conf, env_to_conf_item->conf_name, q, &errmsg2, true, negate,
+                       "environment");
+               if (!ok) {
                        *errmsg = format("%s: %s", key, errmsg2);
                        free(errmsg2);
                        free(key);
@@ -534,147 +630,80 @@ conf_set_value_in_file(const char *path, const char *key, const char *value,
 }
 
 bool
-conf_print_items(struct conf *conf,
-                 void (*printer)(const char *descr, const char *origin,
-                                 void *context),
-                 void *context)
+conf_print_value(struct conf *conf, const char *key,
+                 FILE *file, char **errmsg)
 {
-       char *s = x_strdup("");
-
-       reformat(&s, "base_dir = %s", conf->base_dir);
-       printer(s, conf->item_origins[find_conf("base_dir")->number], context);
-
-       reformat(&s, "cache_dir = %s", conf->cache_dir);
-       printer(s, conf->item_origins[find_conf("cache_dir")->number], context);
-
-       reformat(&s, "cache_dir_levels = %u", conf->cache_dir_levels);
-       printer(s, conf->item_origins[find_conf("cache_dir_levels")->number],
-               context);
-
-       reformat(&s, "compiler = %s", conf->compiler);
-       printer(s, conf->item_origins[find_conf("compiler")->number], context);
-
-       reformat(&s, "compiler_check = %s", conf->compiler_check);
-       printer(s, conf->item_origins[find_conf("compiler_check")->number], context);
-
-       reformat(&s, "compression = %s", bool_to_string(conf->compression));
-       printer(s, conf->item_origins[find_conf("compression")->number], context);
-
-       reformat(&s, "compression_level = %u", conf->compression_level);
-       printer(s, conf->item_origins[find_conf("compression_level")->number],
-               context);
-
-       reformat(&s, "cpp_extension = %s", conf->cpp_extension);
-       printer(s, conf->item_origins[find_conf("cpp_extension")->number], context);
-
-       reformat(&s, "direct_mode = %s", bool_to_string(conf->direct_mode));
-       printer(s, conf->item_origins[find_conf("direct_mode")->number], context);
-
-       reformat(&s, "disable = %s", bool_to_string(conf->disable));
-       printer(s, conf->item_origins[find_conf("disable")->number], context);
-
-       reformat(&s, "extra_files_to_hash = %s", conf->extra_files_to_hash);
-       printer(s, conf->item_origins[find_conf("extra_files_to_hash")->number],
-               context);
-
-       reformat(&s, "hard_link = %s", bool_to_string(conf->hard_link));
-       printer(s, conf->item_origins[find_conf("hard_link")->number], context);
-
-       reformat(&s, "hash_dir = %s", bool_to_string(conf->hash_dir));
-       printer(s, conf->item_origins[find_conf("hash_dir")->number], context);
-
-       reformat(&s, "ignore_headers_in_manifest = %s",
-                conf->ignore_headers_in_manifest);
-       printer(s,
-               conf->item_origins[find_conf("ignore_headers_in_manifest")->number],
-               context);
-
-       reformat(&s, "keep_comments_cpp = %s",
-                bool_to_string(conf->keep_comments_cpp));
-       printer(s, conf->item_origins[find_conf(
-                                       "keep_comments_cpp")->number], context);
-
-       reformat(&s, "limit_multiple = %.1f", (double)conf->limit_multiple);
-       printer(s, conf->item_origins[find_conf("limit_multiple")->number], context);
-
-       reformat(&s, "log_file = %s", conf->log_file);
-       printer(s, conf->item_origins[find_conf("log_file")->number], context);
-
-       reformat(&s, "max_files = %u", conf->max_files);
-       printer(s, conf->item_origins[find_conf("max_files")->number], context);
-
-       char *s2 = format_parsable_size_with_suffix(conf->max_size);
-       reformat(&s, "max_size = %s", s2);
-       printer(s, conf->item_origins[find_conf("max_size")->number], context);
-       free(s2);
-
-       reformat(&s, "path = %s", conf->path);
-       printer(s, conf->item_origins[find_conf("path")->number], context);
-
-       reformat(&s, "prefix_command = %s", conf->prefix_command);
-       printer(s, conf->item_origins[find_conf("prefix_command")->number], context);
-
-       reformat(&s, "prefix_command_cpp = %s", conf->prefix_command_cpp);
-       printer(s, conf->item_origins[find_conf(
-                                       "prefix_command_cpp")->number], context);
-
-       reformat(&s, "read_only = %s", bool_to_string(conf->read_only));
-       printer(s, conf->item_origins[find_conf("read_only")->number], context);
-
-       reformat(&s, "read_only_direct = %s", bool_to_string(conf->read_only_direct));
-       printer(s, conf->item_origins[find_conf("read_only_direct")->number],
-               context);
-
-       reformat(&s, "recache = %s", bool_to_string(conf->recache));
-       printer(s, conf->item_origins[find_conf("recache")->number], context);
-
-       reformat(&s, "run_second_cpp = %s", bool_to_string(conf->run_second_cpp));
-       printer(s, conf->item_origins[find_conf("run_second_cpp")->number], context);
-
-       reformat(&s, "sloppiness = ");
-       if (conf->sloppiness & SLOPPY_FILE_MACRO) {
-               reformat(&s, "%sfile_macro, ", s);
-       }
-       if (conf->sloppiness & SLOPPY_INCLUDE_FILE_MTIME) {
-               reformat(&s, "%sinclude_file_mtime, ", s);
-       }
-       if (conf->sloppiness & SLOPPY_INCLUDE_FILE_CTIME) {
-               reformat(&s, "%sinclude_file_ctime, ", s);
-       }
-       if (conf->sloppiness & SLOPPY_TIME_MACROS) {
-               reformat(&s, "%stime_macros, ", s);
-       }
-       if (conf->sloppiness & SLOPPY_PCH_DEFINES) {
-               reformat(&s, "%spch_defines, ", s);
-       }
-       if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
-               reformat(&s, "%sfile_stat_matches, ", s);
-       }
-       if (conf->sloppiness & SLOPPY_NO_SYSTEM_HEADERS) {
-               reformat(&s, "%sno_system_headers, ", s);
-       }
-       if (conf->sloppiness) {
-               // Strip last ", ".
-               s[strlen(s) - 2] = '\0';
+       const struct conf_item *item = find_conf(key);
+       if (!item) {
+               *errmsg = format("unknown configuration option \"%s\"", key);
+               return false;
        }
-       printer(s, conf->item_origins[find_conf("sloppiness")->number], context);
-
-       reformat(&s, "stats = %s", bool_to_string(conf->stats));
-       printer(s, conf->item_origins[find_conf("stats")->number], context);
-
-       reformat(&s, "temporary_dir = %s", conf->temporary_dir);
-       printer(s, conf->item_origins[find_conf("temporary_dir")->number], context);
+       void *value = (char *)conf + item->offset;
+       char *str = (char *)item->formatter(value);
+       fprintf(file, "%s\n", str);
+       free(str);
+       return true;
+}
 
-       if (conf->umask == UINT_MAX) {
-               reformat(&s, "umask = ");
-       } else {
-               reformat(&s, "umask = %03o", conf->umask);
+static bool
+print_item(struct conf *conf, const char *key,
+           void (*printer)(const char *descr, const char *origin,
+                           void *context),
+           void *context)
+{
+       const struct conf_item *item = find_conf(key);
+       if (!item) {
+               return false;
        }
-       printer(s, conf->item_origins[find_conf("umask")->number], context);
-
-       reformat(&s, "unify = %s", bool_to_string(conf->unify));
-       printer(s, conf->item_origins[find_conf("unify")->number], context);
-
-       free(s);
+       void *value = (char *)conf + item->offset;
+       char *str = (char *)item->formatter(value);
+       char *buf = x_strdup("");
+       reformat(&buf, "%s = %s", key, str);
+       printer(buf, conf->item_origins[item->number], context);
+       free(buf);
+       free(str);
        return true;
 }
+
+bool
+conf_print_items(struct conf *conf,
+                 void (*printer)(const char *descr, const char *origin,
+                                 void *context),
+                 void *context)
+{
+       bool ok = true;
+       ok &= print_item(conf, "base_dir", printer, context);
+       ok &= print_item(conf, "cache_dir", printer, context);
+       ok &= print_item(conf, "cache_dir_levels", printer, context);
+       ok &= print_item(conf, "compiler", printer, context);
+       ok &= print_item(conf, "compiler_check", printer, context);
+       ok &= print_item(conf, "compression", printer, context);
+       ok &= print_item(conf, "compression_level", printer, context);
+       ok &= print_item(conf, "cpp_extension", printer, context);
+       ok &= print_item(conf, "debug", printer, context);
+       ok &= print_item(conf, "direct_mode", printer, context);
+       ok &= print_item(conf, "disable", printer, context);
+       ok &= print_item(conf, "extra_files_to_hash", printer, context);
+       ok &= print_item(conf, "hard_link", printer, context);
+       ok &= print_item(conf, "hash_dir", printer, context);
+       ok &= print_item(conf, "ignore_headers_in_manifest", printer, context);
+       ok &= print_item(conf, "keep_comments_cpp", printer, context);
+       ok &= print_item(conf, "limit_multiple", printer, context);
+       ok &= print_item(conf, "log_file", printer, context);
+       ok &= print_item(conf, "max_files", printer, context);
+       ok &= print_item(conf, "max_size", printer, context);
+       ok &= print_item(conf, "path", printer, context);
+       ok &= print_item(conf, "pch_external_checksum", printer, context);
+       ok &= print_item(conf, "prefix_command", printer, context);
+       ok &= print_item(conf, "prefix_command_cpp", printer, context);
+       ok &= print_item(conf, "read_only", printer, context);
+       ok &= print_item(conf, "read_only_direct", printer, context);
+       ok &= print_item(conf, "recache", printer, context);
+       ok &= print_item(conf, "run_second_cpp", printer, context);
+       ok &= print_item(conf, "sloppiness", printer, context);
+       ok &= print_item(conf, "stats", printer, context);
+       ok &= print_item(conf, "temporary_dir", printer, context);
+       ok &= print_item(conf, "umask", printer, context);
+       ok &= print_item(conf, "unify", printer, context);
+       return ok;
+}
index 232dcfd552d402a6cf731164fd3e974d5d7c7875..9c9e28f42cf02e98de4be994daac39a27a9a6b27 100644 (file)
@@ -12,6 +12,7 @@ struct conf {
        bool compression;
        unsigned compression_level;
        char *cpp_extension;
+       bool debug;
        bool direct_mode;
        bool disable;
        char *extra_files_to_hash;
@@ -24,6 +25,7 @@ struct conf {
        unsigned max_files;
        uint64_t max_size;
        char *path;
+       bool pch_external_checksum;
        char *prefix_command;
        char *prefix_command_cpp;
        bool read_only;
@@ -43,6 +45,8 @@ struct conf *conf_create(void);
 void conf_free(struct conf *conf);
 bool conf_read(struct conf *conf, const char *path, char **errmsg);
 bool conf_update_from_environment(struct conf *conf, char **errmsg);
+bool conf_print_value(struct conf *conf, const char *key,
+                      FILE *file, char **errmsg);
 bool conf_set_value_in_file(const char *path, const char *key,
                             const char *value, char **errmsg);
 bool conf_print_items(struct conf *conf,
index 531bc92d8a6b9c388cdc7226dc0d612e9dfdf23a..f3954b55969e77aa9e6859893bbab7160edcf16e 100644 (file)
@@ -4,7 +4,7 @@
 %readonly-tables
 %define hash-function-name confitems_hash
 %define lookup-function-name confitems_get
-%define initializer-suffix ,0,NULL,0,NULL
+%define initializer-suffix ,0,NULL,0,NULL,NULL
 struct conf_item;
 %%
 base_dir,             0, ITEM_V(base_dir, env_string, absolute_path)
@@ -15,26 +15,28 @@ compiler_check,       4, ITEM(compiler_check, string)
 compression,          5, ITEM(compression, bool)
 compression_level,    6, ITEM(compression_level, unsigned)
 cpp_extension,        7, ITEM(cpp_extension, string)
-direct_mode,          8, ITEM(direct_mode, bool)
-disable,              9, ITEM(disable, bool)
-extra_files_to_hash, 10, ITEM(extra_files_to_hash, env_string)
-hard_link,           11, ITEM(hard_link, bool)
-hash_dir,            12, ITEM(hash_dir, bool)
-ignore_headers_in_manifest, 13, ITEM(ignore_headers_in_manifest, env_string)
-keep_comments_cpp,   14, ITEM(keep_comments_cpp, bool)
-limit_multiple,      15, ITEM(limit_multiple, float)
-log_file,            16, ITEM(log_file, env_string)
-max_files,           17, ITEM(max_files, unsigned)
-max_size,            18, ITEM(max_size, size)
-path,                19, ITEM(path, env_string)
-prefix_command,      20, ITEM(prefix_command, env_string)
-prefix_command_cpp,  21, ITEM(prefix_command_cpp, env_string)
-read_only,           22, ITEM(read_only, bool)
-read_only_direct,    23, ITEM(read_only_direct, bool)
-recache,             24, ITEM(recache, bool)
-run_second_cpp,      25, ITEM(run_second_cpp, bool)
-sloppiness,          26, ITEM(sloppiness, sloppiness)
-stats,               27, ITEM(stats, bool)
-temporary_dir,       28, ITEM(temporary_dir, env_string)
-umask,               29, ITEM(umask, umask)
-unify,               30, ITEM(unify, bool)
+debug,                8, ITEM(debug, bool)
+direct_mode,          9, ITEM(direct_mode, bool)
+disable,             10, ITEM(disable, bool)
+extra_files_to_hash, 11, ITEM(extra_files_to_hash, env_string)
+hard_link,           12, ITEM(hard_link, bool)
+hash_dir,            13, ITEM(hash_dir, bool)
+ignore_headers_in_manifest, 14, ITEM(ignore_headers_in_manifest, env_string)
+keep_comments_cpp,   15, ITEM(keep_comments_cpp, bool)
+limit_multiple,      16, ITEM(limit_multiple, float)
+log_file,            17, ITEM(log_file, env_string)
+max_files,           18, ITEM(max_files, unsigned)
+max_size,            19, ITEM(max_size, size)
+path,                20, ITEM(path, env_string)
+pch_external_checksum, 21, ITEM(pch_external_checksum, bool)
+prefix_command,      22, ITEM(prefix_command, env_string)
+prefix_command_cpp,  23, ITEM(prefix_command_cpp, env_string)
+read_only,           24, ITEM(read_only, bool)
+read_only_direct,    25, ITEM(read_only_direct, bool)
+recache,             26, ITEM(recache, bool)
+run_second_cpp,      27, ITEM(run_second_cpp, bool)
+sloppiness,          28, ITEM(sloppiness, sloppiness)
+stats,               29, ITEM(stats, bool)
+temporary_dir,       30, ITEM(temporary_dir, env_string)
+umask,               31, ITEM(umask, umask)
+unify,               32, ITEM(unify, bool)
index 63f0da0900b5fa29b3493c0b2e1d9e499e14f54e..b8f6869936ea6b207c0da51360f2dea23708c626 100644 (file)
@@ -31,7 +31,7 @@
 
 #line 8 "src/confitems.gperf"
 struct conf_item;
-/* maximum key range = 46, duplicates = 0 */
+/* maximum key range = 48, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -45,32 +45,32 @@ confitems_hash (register const char *str, register unsigned int len)
 {
   static const unsigned char asso_values[] =
     {
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50,  0, 13,  0,
-       5, 10, 50,  0, 30, 20, 50,  0, 10, 20,
-       5,  0,  0, 50,  5,  0, 10, 15, 50, 50,
-      20, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
-      50, 50, 50, 50, 50, 50
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52,  0, 35,  0,
+       0, 10, 52,  0, 30, 25, 52,  0, 10, 20,
+      10,  0,  0, 52,  5,  5, 10, 15, 52, 52,
+      15, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+      52, 52, 52, 52, 52, 52
     };
   return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
 }
@@ -87,91 +87,94 @@ confitems_get (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 31,
+      TOTAL_KEYWORDS = 33,
       MIN_WORD_LENGTH = 4,
       MAX_WORD_LENGTH = 26,
       MIN_HASH_VALUE = 4,
-      MAX_HASH_VALUE = 49
+      MAX_HASH_VALUE = 51
     };
 
   static const struct conf_item wordlist[] =
     {
-      {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
-      {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
-#line 29 "src/confitems.gperf"
-      {"path",                19, ITEM(path, env_string)},
-      {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
-      {"",0,NULL,0,NULL},
+      {"",0,NULL,0,NULL,NULL}, {"",0,NULL,0,NULL,NULL},
+      {"",0,NULL,0,NULL,NULL}, {"",0,NULL,0,NULL,NULL},
+#line 30 "src/confitems.gperf"
+      {"path",                20, ITEM(path, env_string)},
+      {"",0,NULL,0,NULL,NULL}, {"",0,NULL,0,NULL,NULL},
+      {"",0,NULL,0,NULL,NULL},
 #line 13 "src/confitems.gperf"
       {"compiler",             3, ITEM(compiler, string)},
 #line 11 "src/confitems.gperf"
       {"cache_dir",            1, ITEM(cache_dir, env_string)},
-      {"",0,NULL,0,NULL},
+      {"",0,NULL,0,NULL,NULL},
 #line 15 "src/confitems.gperf"
       {"compression",          5, ITEM(compression, bool)},
-      {"",0,NULL,0,NULL},
+      {"",0,NULL,0,NULL,NULL},
 #line 17 "src/confitems.gperf"
       {"cpp_extension",        7, ITEM(cpp_extension, string)},
 #line 14 "src/confitems.gperf"
       {"compiler_check",       4, ITEM(compiler_check, string)},
-#line 37 "src/confitems.gperf"
-      {"stats",               27, ITEM(stats, bool)},
+#line 18 "src/confitems.gperf"
+      {"debug",                8, ITEM(debug, bool)},
 #line 12 "src/confitems.gperf"
       {"cache_dir_levels",     2, ITEM_V(cache_dir_levels, unsigned, dir_levels)},
 #line 16 "src/confitems.gperf"
       {"compression_level",    6, ITEM(compression_level, unsigned)},
-#line 26 "src/confitems.gperf"
-      {"log_file",            16, ITEM(log_file, env_string)},
-#line 30 "src/confitems.gperf"
-      {"prefix_command",      20, ITEM(prefix_command, env_string)},
-#line 36 "src/confitems.gperf"
-      {"sloppiness",          26, ITEM(sloppiness, sloppiness)},
-#line 10 "src/confitems.gperf"
-      {"base_dir",             0, ITEM_V(base_dir, env_string, absolute_path)},
-#line 34 "src/confitems.gperf"
-      {"recache",             24, ITEM(recache, bool)},
-#line 31 "src/confitems.gperf"
-      {"prefix_command_cpp",  21, ITEM(prefix_command_cpp, env_string)},
-#line 32 "src/confitems.gperf"
-      {"read_only",           22, ITEM(read_only, bool)},
-#line 40 "src/confitems.gperf"
-      {"unify",               30, ITEM(unify, bool)},
-      {"",0,NULL,0,NULL},
-#line 24 "src/confitems.gperf"
-      {"keep_comments_cpp",   14, ITEM(keep_comments_cpp, bool)},
-#line 28 "src/confitems.gperf"
-      {"max_size",            18, ITEM(max_size, size)},
 #line 27 "src/confitems.gperf"
-      {"max_files",           17, ITEM(max_files, unsigned)},
-      {"",0,NULL,0,NULL},
+      {"log_file",            17, ITEM(log_file, env_string)},
+#line 32 "src/confitems.gperf"
+      {"prefix_command",      22, ITEM(prefix_command, env_string)},
+#line 39 "src/confitems.gperf"
+      {"stats",               29, ITEM(stats, bool)},
+#line 31 "src/confitems.gperf"
+      {"pch_external_checksum", 21, ITEM(pch_external_checksum, bool)},
+#line 36 "src/confitems.gperf"
+      {"recache",             26, ITEM(recache, bool)},
 #line 33 "src/confitems.gperf"
-      {"read_only_direct",    23, ITEM(read_only_direct, bool)},
-#line 19 "src/confitems.gperf"
-      {"disable",              9, ITEM(disable, bool)},
+      {"prefix_command_cpp",  23, ITEM(prefix_command_cpp, env_string)},
+#line 34 "src/confitems.gperf"
+      {"read_only",           24, ITEM(read_only, bool)},
 #line 38 "src/confitems.gperf"
-      {"temporary_dir",       28, ITEM(temporary_dir, env_string)},
+      {"sloppiness",          28, ITEM(sloppiness, sloppiness)},
+      {"",0,NULL,0,NULL,NULL},
+#line 25 "src/confitems.gperf"
+      {"keep_comments_cpp",   15, ITEM(keep_comments_cpp, bool)},
+#line 29 "src/confitems.gperf"
+      {"max_size",            19, ITEM(max_size, size)},
+#line 28 "src/confitems.gperf"
+      {"max_files",           18, ITEM(max_files, unsigned)},
+#line 42 "src/confitems.gperf"
+      {"unify",               32, ITEM(unify, bool)},
 #line 35 "src/confitems.gperf"
-      {"run_second_cpp",      25, ITEM(run_second_cpp, bool)},
-      {"",0,NULL,0,NULL},
-#line 18 "src/confitems.gperf"
-      {"direct_mode",          8, ITEM(direct_mode, bool)},
-      {"",0,NULL,0,NULL},
+      {"read_only_direct",    25, ITEM(read_only_direct, bool)},
+#line 20 "src/confitems.gperf"
+      {"disable",             10, ITEM(disable, bool)},
+#line 40 "src/confitems.gperf"
+      {"temporary_dir",       30, ITEM(temporary_dir, env_string)},
+#line 37 "src/confitems.gperf"
+      {"run_second_cpp",      27, ITEM(run_second_cpp, bool)},
+      {"",0,NULL,0,NULL,NULL},
+#line 19 "src/confitems.gperf"
+      {"direct_mode",          9, ITEM(direct_mode, bool)},
+      {"",0,NULL,0,NULL,NULL},
+#line 23 "src/confitems.gperf"
+      {"hash_dir",            13, ITEM(hash_dir, bool)},
 #line 22 "src/confitems.gperf"
-      {"hash_dir",            12, ITEM(hash_dir, bool)},
+      {"hard_link",           12, ITEM(hard_link, bool)},
+#line 41 "src/confitems.gperf"
+      {"umask",               31, ITEM(umask, umask)},
+      {"",0,NULL,0,NULL,NULL}, {"",0,NULL,0,NULL,NULL},
+#line 10 "src/confitems.gperf"
+      {"base_dir",             0, ITEM_V(base_dir, env_string, absolute_path)},
 #line 21 "src/confitems.gperf"
-      {"hard_link",           11, ITEM(hard_link, bool)},
-#line 39 "src/confitems.gperf"
-      {"umask",               29, ITEM(umask, umask)},
-      {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
-      {"",0,NULL,0,NULL},
-#line 25 "src/confitems.gperf"
-      {"limit_multiple",      15, ITEM(limit_multiple, float)},
-      {"",0,NULL,0,NULL},
-#line 23 "src/confitems.gperf"
-      {"ignore_headers_in_manifest", 13, ITEM(ignore_headers_in_manifest, env_string)},
-      {"",0,NULL,0,NULL}, {"",0,NULL,0,NULL},
-#line 20 "src/confitems.gperf"
-      {"extra_files_to_hash", 10, ITEM(extra_files_to_hash, env_string)}
+      {"extra_files_to_hash", 11, ITEM(extra_files_to_hash, env_string)},
+      {"",0,NULL,0,NULL,NULL}, {"",0,NULL,0,NULL,NULL},
+      {"",0,NULL,0,NULL,NULL}, {"",0,NULL,0,NULL,NULL},
+#line 26 "src/confitems.gperf"
+      {"limit_multiple",      16, ITEM(limit_multiple, float)},
+      {"",0,NULL,0,NULL,NULL},
+#line 24 "src/confitems.gperf"
+      {"ignore_headers_in_manifest", 14, ITEM(ignore_headers_in_manifest, env_string)}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -188,4 +191,4 @@ confitems_get (register const char *str, register unsigned int len)
     }
   return 0;
 }
-static const size_t CONFITEMS_TOTAL_KEYWORDS = 31;
+static const size_t CONFITEMS_TOTAL_KEYWORDS = 33;
index 81d8444ae61f6f76bfd7bc386c376ad480e3309d..4d255190466be0d20c20d1624d2911fcbaa8aa2e 100644 (file)
@@ -10,12 +10,14 @@ struct env_to_conf_item;
 %%
 BASEDIR, "base_dir"
 CC, "compiler"
+COMPILER, "compiler"
 COMPILERCHECK, "compiler_check"
 COMPRESS, "compression"
 COMPRESSLEVEL, "compression_level"
 CPP2, "run_second_cpp"
 COMMENTS, "keep_comments_cpp"
 DIR, "cache_dir"
+DEBUG, "debug"
 DIRECT, "direct_mode"
 DISABLE, "disable"
 EXTENSION, "cpp_extension"
@@ -29,6 +31,7 @@ MAXFILES, "max_files"
 MAXSIZE, "max_size"
 NLEVELS, "cache_dir_levels"
 PATH, "path"
+PCH_EXTSUM, "pch_external_checksum"
 PREFIX, "prefix_command"
 PREFIX_CPP, "prefix_command_cpp"
 READONLY, "read_only"
index 690ed94f56fcf287ead6416426019a7e00ccf23b..b5afa6952fa681864ef28e1610d72990a2e28fa5 100644 (file)
@@ -1,6 +1,6 @@
 /* ANSI-C code produced by gperf version 3.0.4 */
 /* Command-line: gperf src/envtoconfitems.gperf  */
-/* Computed positions: -k'1,5' */
+/* Computed positions: -k'4-5' */
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -31,7 +31,7 @@
 
 #line 9 "src/envtoconfitems.gperf"
 struct env_to_conf_item;
-/* maximum key range = 42, duplicates = 0 */
+/* maximum key range = 52, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
@@ -45,45 +45,45 @@ envtoconfitems_hash (register const char *str, register unsigned int len)
 {
   static const unsigned char asso_values[] =
     {
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 20,  0,  0, 10,
-       0, 44,  5, 15,  0, 44, 10, 25,  9,  0,
-       5, 10,  5, 15, 10,  5, 44, 44, 44, 44,
-       0, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
-      44, 44, 44, 44, 44, 44, 44
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+       0, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 25, 10,  0,  0, 15,
+      10,  0,  5,  0, 54, 10, 35, 15,  0, 25,
+       0, 54, 15, 20,  0,  0, 15, 54, 54,  0,
+      54, 54, 54, 54, 54,  5, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+      54, 54, 54, 54, 54, 54
     };
   register int hval = len;
 
   switch (hval)
     {
       default:
-        hval += asso_values[(unsigned char)str[4]+1];
+        hval += asso_values[(unsigned char)str[4]];
       /*FALLTHROUGH*/
       case 4:
+        hval += asso_values[(unsigned char)str[3]];
+      /*FALLTHROUGH*/
       case 3:
       case 2:
-      case 1:
-        hval += asso_values[(unsigned char)str[0]];
         break;
     }
   return hval;
@@ -101,11 +101,11 @@ envtoconfitems_get (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 31,
+      TOTAL_KEYWORDS = 34,
       MIN_WORD_LENGTH = 2,
       MAX_WORD_LENGTH = 15,
       MIN_HASH_VALUE = 2,
-      MAX_HASH_VALUE = 43
+      MAX_HASH_VALUE = 53
     };
 
   static const struct env_to_conf_item wordlist[] =
@@ -113,75 +113,83 @@ envtoconfitems_get (register const char *str, register unsigned int len)
       {"",""}, {"",""},
 #line 12 "src/envtoconfitems.gperf"
       {"CC", "compiler"},
-#line 18 "src/envtoconfitems.gperf"
+#line 19 "src/envtoconfitems.gperf"
       {"DIR", "cache_dir"},
-#line 16 "src/envtoconfitems.gperf"
+#line 17 "src/envtoconfitems.gperf"
       {"CPP2", "run_second_cpp"},
-      {"",""},
-#line 19 "src/envtoconfitems.gperf"
-      {"DIRECT", "direct_mode"},
 #line 20 "src/envtoconfitems.gperf"
-      {"DISABLE", "disable"},
-#line 17 "src/envtoconfitems.gperf"
-      {"COMMENTS", "keep_comments_cpp"},
-#line 31 "src/envtoconfitems.gperf"
-      {"PATH", "path"},
-#line 41 "src/envtoconfitems.gperf"
-      {"UNIFY", "unify"},
-#line 32 "src/envtoconfitems.gperf"
-      {"PREFIX", "prefix_command"},
-#line 36 "src/envtoconfitems.gperf"
-      {"RECACHE", "recache"},
-#line 13 "src/envtoconfitems.gperf"
-      {"COMPILERCHECK", "compiler_check"},
+      {"DEBUG", "debug"},
       {"",""},
+#line 42 "src/envtoconfitems.gperf"
+      {"TEMPDIR", "temporary_dir"},
+#line 13 "src/envtoconfitems.gperf"
+      {"COMPILER", "compiler"},
 #line 33 "src/envtoconfitems.gperf"
-      {"PREFIX_CPP", "prefix_command_cpp"},
-#line 30 "src/envtoconfitems.gperf"
-      {"NLEVELS", "cache_dir_levels"},
-#line 27 "src/envtoconfitems.gperf"
-      {"LOGFILE", "log_file"},
-#line 34 "src/envtoconfitems.gperf"
-      {"READONLY", "read_only"},
-#line 21 "src/envtoconfitems.gperf"
-      {"EXTENSION", "cpp_extension"},
+      {"PATH", "path"},
 #line 40 "src/envtoconfitems.gperf"
-      {"UMASK", "umask"},
+      {"SLOPPINESS", "sloppiness"},
       {"",""},
-#line 24 "src/envtoconfitems.gperf"
+#line 26 "src/envtoconfitems.gperf"
       {"HASHDIR", "hash_dir"},
 #line 14 "src/envtoconfitems.gperf"
-      {"COMPRESS", "compression"},
-      {"",""},
+      {"COMPILERCHECK", "compiler_check"},
+#line 28 "src/envtoconfitems.gperf"
+      {"LIMIT_MULTIPLE", "limit_multiple"},
+#line 44 "src/envtoconfitems.gperf"
+      {"UNIFY", "unify"},
 #line 35 "src/envtoconfitems.gperf"
-      {"READONLY_DIRECT", "read_only_direct"},
+      {"PREFIX", "prefix_command"},
+#line 29 "src/envtoconfitems.gperf"
+      {"LOGFILE", "log_file"},
+#line 30 "src/envtoconfitems.gperf"
+      {"MAXFILES", "max_files"},
       {"",""},
-#line 39 "src/envtoconfitems.gperf"
-      {"TEMPDIR", "temporary_dir"},
+#line 36 "src/envtoconfitems.gperf"
+      {"PREFIX_CPP", "prefix_command_cpp"},
+#line 21 "src/envtoconfitems.gperf"
+      {"DIRECT", "direct_mode"},
+#line 11 "src/envtoconfitems.gperf"
+      {"BASEDIR", "base_dir"},
 #line 15 "src/envtoconfitems.gperf"
-      {"COMPRESSLEVEL", "compression_level"},
-#line 26 "src/envtoconfitems.gperf"
-      {"LIMIT_MULTIPLE", "limit_multiple"},
-#line 38 "src/envtoconfitems.gperf"
+      {"COMPRESS", "compression"},
+#line 23 "src/envtoconfitems.gperf"
+      {"EXTENSION", "cpp_extension"},
+#line 41 "src/envtoconfitems.gperf"
       {"STATS", "stats"},
       {"",""},
-#line 29 "src/envtoconfitems.gperf"
+#line 31 "src/envtoconfitems.gperf"
       {"MAXSIZE", "max_size"},
-#line 28 "src/envtoconfitems.gperf"
-      {"MAXFILES", "max_files"},
+#line 16 "src/envtoconfitems.gperf"
+      {"COMPRESSLEVEL", "compression_level"},
+      {"",""},
+#line 34 "src/envtoconfitems.gperf"
+      {"PCH_EXTSUM", "pch_external_checksum"},
       {"",""},
+#line 39 "src/envtoconfitems.gperf"
+      {"RECACHE", "recache"},
 #line 37 "src/envtoconfitems.gperf"
-      {"SLOPPINESS", "sloppiness"},
+      {"READONLY", "read_only"},
       {"",""},
-#line 11 "src/envtoconfitems.gperf"
-      {"BASEDIR", "base_dir"},
-#line 23 "src/envtoconfitems.gperf"
-      {"HARDLINK", "hard_link"},
+#line 43 "src/envtoconfitems.gperf"
+      {"UMASK", "umask"},
+      {"",""},
+#line 32 "src/envtoconfitems.gperf"
+      {"NLEVELS", "cache_dir_levels"},
+#line 18 "src/envtoconfitems.gperf"
+      {"COMMENTS", "keep_comments_cpp"},
+      {"",""},
+#line 38 "src/envtoconfitems.gperf"
+      {"READONLY_DIRECT", "read_only_direct"},
       {"",""},
 #line 22 "src/envtoconfitems.gperf"
+      {"DISABLE", "disable"},
+#line 25 "src/envtoconfitems.gperf"
+      {"HARDLINK", "hard_link"},
+      {"",""}, {"",""}, {"",""}, {"",""}, {"",""}, {"",""},
+#line 24 "src/envtoconfitems.gperf"
       {"EXTRAFILES", "extra_files_to_hash"},
       {"",""}, {"",""},
-#line 25 "src/envtoconfitems.gperf"
+#line 27 "src/envtoconfitems.gperf"
       {"IGNOREHEADERS", "ignore_headers_in_manifest"}
     };
 
@@ -199,4 +207,4 @@ envtoconfitems_get (register const char *str, register unsigned int len)
     }
   return 0;
 }
-static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 31;
+static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 34;
index ae30552030725397561f8f02f005fa8a8d9cf8f9..ca72d2762d16777a0e4c5c85847f36ed63f91df1 100644 (file)
@@ -40,7 +40,7 @@ win32argvtos(char *prefix, char **argv)
                                break;
                        case '"':
                                bs = (bs << 1) + 1;
-                               // Fallthrough.
+                       // Fallthrough.
                        default:
                                k += bs + 1;
                                bs = 0;
@@ -167,8 +167,8 @@ win32execute(char *path, char **argv, int doreturn,
        char full_path_win_ext[MAX_PATH] = {0};
        add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path);
        BOOL ret =
-         CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
-                       &si, &pi);
+               CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
+                             &si, &pi);
        if (fd_stdout != -1) {
                close(fd_stdout);
                close(fd_stderr);
@@ -178,17 +178,17 @@ win32execute(char *path, char **argv, int doreturn,
                LPVOID lpMsgBuf;
                DWORD dw = GetLastError();
                FormatMessage(
-                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                 FORMAT_MESSAGE_FROM_SYSTEM |
-                 FORMAT_MESSAGE_IGNORE_INSERTS,
-                 NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
-                 0, NULL);
+                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
+                       0, NULL);
 
                LPVOID lpDisplayBuf =
-                 (LPVOID) LocalAlloc(LMEM_ZEROINIT,
-                                     (lstrlen((LPCTSTR) lpMsgBuf)
-                                      + lstrlen((LPCTSTR) __FILE__) + 200)
-                                     * sizeof(TCHAR));
+                       (LPVOID) LocalAlloc(LMEM_ZEROINIT,
+                                           (lstrlen((LPCTSTR) lpMsgBuf)
+                                            + lstrlen((LPCTSTR) __FILE__) + 200)
+                                           * sizeof(TCHAR));
                _snprintf((LPTSTR) lpDisplayBuf,
                          LocalSize(lpDisplayBuf) / sizeof(TCHAR),
                          TEXT("%s failed with error %lu: %s"), __FILE__, dw,
@@ -348,3 +348,27 @@ print_command(FILE *fp, char **argv)
        }
        fprintf(fp, "\n");
 }
+
+char *
+format_command(char **argv)
+{
+       size_t len = 0;
+       for (int i = 0; argv[i]; i++) {
+               len += (i == 0) ? 0 : 1;
+               len += strlen(argv[i]);
+       }
+       len += 1;
+       char *buf = x_malloc(len + 1);
+       char *p = buf;
+       for (int i = 0; argv[i]; i++) {
+               if (i != 0) {
+                       *p++ = ' ';
+               }
+               for (char *q = argv[i]; *q != '\0'; q++) {
+                       *p++ = *q;
+               }
+       }
+       *p++ = '\n';
+       *p++ = '\0';
+       return buf;
+}
index 5c2c482cf656fc40d70f6388945a3a5b0bb9c7f3..5be5e2201ac325721024e8dfb6c2d9fd6427bd61 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2010-2016 Joel Rosdahl
+// Copyright (C) 2010-2018 Joel Rosdahl
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by the Free
@@ -56,7 +56,7 @@ exitfn_add_nullary(void (*function)(void))
 }
 
 // Add a function to be called with a context parameter when ccache exits.
-// Functions are called in reverse order.
+// Functions are called in LIFO order except when added via exitfn_add_last.
 void
 exitfn_add(void (*function)(void *), void *context)
 {
@@ -67,6 +67,24 @@ exitfn_add(void (*function)(void *), void *context)
        exit_functions = p;
 }
 
+// Add a function to be called with a context parameter when ccache exits. In
+// contrast to exitfn_add, exitfn_add_last sets up the function to be called
+// last.
+void
+exitfn_add_last(void (*function)(void *), void *context)
+{
+       struct exit_function *p = x_malloc(sizeof(*p));
+       p->function = function;
+       p->context = context;
+       p->next = NULL;
+
+       struct exit_function **q = &exit_functions;
+       while (*q) {
+               q = &(*q)->next;
+       }
+       *q = p;
+}
+
 // Call added functions.
 void
 exitfn_call(void)
diff --git a/src/getopt_long.c b/src/getopt_long.c
deleted file mode 100644 (file)
index 61141c2..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * getopt_long() -- long options parser
- *
- * Portions Copyright (c) 1987, 1993, 1994
- * The Regents of the University of California.  All rights reserved.
- *
- * Portions Copyright (c) 2003
- * PostgreSQL Global Development Group
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#ifndef HAVE_GETOPT_LONG
-
-#include "getopt_long.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#define BADCH  '?'
-#define BADARG ':'
-#define EMSG   ""
-
-int
-getopt_long(int argc, char *const argv[],
-            const char *optstring,
-            const struct option * longopts, int *longindex)
-{
-       static char *place = EMSG; /* option letter processing */
-       char        *oli;          /* option letter list index */
-
-       if (!*place)
-       { /* update scanning pointer */
-               if (optind >= argc)
-               {
-                       place = EMSG;
-                       return -1;
-               }
-
-               place = argv[optind];
-
-               if (place[0] != '-')
-               {
-                       place = EMSG;
-                       return -1;
-               }
-
-               place++;
-
-               if (place[0] == '-' && place[1] == '\0')
-               { /* found "--" */
-                       ++optind;
-                       place = EMSG;
-                       return -1;
-               }
-
-               if (place[0] == '-' && place[1])
-               {
-                       /* long option */
-                       size_t namelen;
-                       int    i;
-
-                       place++;
-
-                       namelen = strcspn(place, "=");
-                       for (i = 0; longopts[i].name != NULL; i++)
-                       {
-                               if (strlen(longopts[i].name) == namelen
-                                       && strncmp(place, longopts[i].name, namelen) == 0)
-                               {
-                                       if (longopts[i].has_arg)
-                                       {
-                                               if (place[namelen] == '=')
-                                                       optarg = place + namelen + 1;
-                                               else if (optind < argc - 1)
-                                               {
-                                                       optind++;
-                                                       optarg = argv[optind];
-                                               }
-                                               else
-                                               {
-                                                       if (optstring[0] == ':')
-                                                               return BADARG;
-                                                       if (opterr)
-                                                               fprintf(stderr,
-                                                                       "%s: option requires an argument -- %s\n",
-                                                                       argv[0], place);
-                                                       place = EMSG;
-                                                       optind++;
-                                                       return BADCH;
-                                               }
-                                       }
-                                       else
-                                       {
-                                               optarg = NULL;
-                                               if (place[namelen] != 0)
-                                               {
-                                                       /* XXX error? */
-                                               }
-                                       }
-
-                                       optind++;
-
-                                       if (longindex)
-                                               *longindex = i;
-
-                                       place = EMSG;
-
-                                       if (longopts[i].flag == NULL)
-                                               return longopts[i].val;
-                                       else
-                                       {
-                                               *longopts[i].flag = longopts[i].val;
-                                               return 0;
-                                       }
-                               }
-                       }
-
-                       if (opterr && optstring[0] != ':')
-                               fprintf(stderr,
-                                       "%s: illegal option -- %s\n", argv[0], place);
-                       place = EMSG;
-                       optind++;
-                       return BADCH;
-               }
-       }
-
-       /* short option */
-       optopt = (int) *place++;
-
-       oli = strchr(optstring, optopt);
-       if (!oli)
-       {
-               if (!*place)
-                       ++optind;
-               if (opterr && *optstring != ':')
-                       fprintf(stderr,
-                               "%s: illegal option -- %c\n", argv[0], optopt);
-               return BADCH;
-       }
-
-       if (oli[1] != ':')
-       { /* don't need argument */
-               optarg = NULL;
-               if (!*place)
-                       ++optind;
-       }
-       else
-       { /* need an argument */
-               if (*place) /* no white space */
-                       optarg = place;
-               else if (argc <= ++optind)
-               { /* no arg */
-                       place = EMSG;
-                       if (*optstring == ':')
-                               return BADARG;
-                       if (opterr)
-                               fprintf(stderr,
-                                       "%s: option requires an argument -- %c\n",
-                                       argv[0], optopt);
-                       return BADCH;
-               }
-               else
-                       /* white space */
-                       optarg = argv[optind];
-               place = EMSG;
-               ++optind;
-       }
-       return optopt;
-}
-
-#endif /* HAVE_GETOPT_LONG */
index 3b462ca9eaf7ad22c0af43a8dd577691a945e481..8a92085fae1a8356b19bd2115c2392243acbaa12 100644 (file)
@@ -1,5 +1,5 @@
 // Copyright (C) 2002 Andrew Tridgell
-// Copyright (C) 2010-2016 Joel Rosdahl
+// Copyright (C) 2010-2018 Joel Rosdahl
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by the Free
 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 #include "ccache.h"
+#include "hash.h"
+#include "mdfour.h"
 
 #define HASH_DELIMITER "\000cCaChE"
 
-void
-hash_start(struct mdfour *md)
+struct hash {
+       struct mdfour md;
+       FILE *debug_binary;
+       FILE *debug_text;
+};
+
+static void
+do_hash_buffer(struct hash *hash, const void *s, size_t len)
+{
+       mdfour_update(&hash->md, (const unsigned char *)s, len);
+       if (len > 0 && hash->debug_binary) {
+               fwrite(s, 1, len, hash->debug_binary);
+       }
+}
+
+static void
+do_debug_text(struct hash *hash, const void *s, size_t len)
+{
+       if (len > 0 && hash->debug_text) {
+               fwrite(s, 1, len, hash->debug_text);
+       }
+}
+
+struct hash *
+hash_init(void)
+{
+       struct hash *hash = malloc(sizeof(struct hash));
+       mdfour_begin(&hash->md);
+       hash->debug_binary = NULL;
+       hash->debug_text = NULL;
+       return hash;
+}
+
+struct hash *
+hash_copy(struct hash *hash)
 {
-       mdfour_begin(md);
+       struct hash *result = malloc(sizeof(struct hash));
+       result->md = hash->md;
+       result->debug_binary = NULL;
+       result->debug_text = NULL;
+       return result;
+}
+
+void hash_free(struct hash *hash)
+{
+       free(hash);
+}
+
+void hash_enable_debug(
+       struct hash *hash, const char *section_name,
+       FILE *debug_binary, FILE *debug_text)
+{
+       hash->debug_binary = debug_binary;
+       hash->debug_text = debug_text;
+
+       do_debug_text(hash, "=== ", 4);
+       do_debug_text(hash, section_name, strlen(section_name));
+       do_debug_text(hash, " ===\n", 5);
+}
+
+size_t
+hash_input_size(struct hash *hash)
+{
+       return hash->md.totalN;
 }
 
 void
-hash_buffer(struct mdfour *md, const void *s, size_t len)
+hash_buffer(struct hash *hash, const void *s, size_t len)
 {
-       mdfour_update(md, (unsigned char *)s, len);
+       do_hash_buffer(hash, s, len);
+       do_debug_text(hash, s, len);
 }
 
-// Return the hash result as a hex string. Caller frees.
 char *
-hash_result(struct mdfour *md)
+hash_result(struct hash *hash)
 {
        unsigned char sum[16];
 
-       hash_result_as_bytes(md, sum);
-       return format_hash_as_string(sum, (unsigned) md->totalN);
+       hash_result_as_bytes(hash, sum);
+       return format_hash_as_string(sum, (unsigned) hash->md.totalN);
 }
 
-// Return the hash result as 16 binary bytes.
 void
-hash_result_as_bytes(struct mdfour *md, unsigned char *out)
+hash_result_as_bytes(struct hash *hash, unsigned char *out)
 {
-       hash_buffer(md, NULL, 0);
-       mdfour_result(md, out);
+       mdfour_update(&hash->md, NULL, 0);
+       mdfour_result(&hash->md, out);
 }
 
 bool
-hash_equal(struct mdfour *md1, struct mdfour *md2)
+hash_equal(struct hash *hash1, struct hash *hash2)
 {
        unsigned char sum1[16];
-       hash_result_as_bytes(md1, sum1);
+       hash_result_as_bytes(hash1, sum1);
        unsigned char sum2[16];
-       hash_result_as_bytes(md2, sum2);
+       hash_result_as_bytes(hash2, sum2);
        return memcmp(sum1, sum2, sizeof(sum1)) == 0;
 }
 
-// Hash some data that is unlikely to occur in the input. The idea is twofold:
-//
-// - Delimit things like arguments from each other (e.g., so that -I -O2 and
-//   -I-O2 hash differently).
-// - Tag different types of hashed information so that it's possible to do
-//   conditional hashing of information in a safe way (e.g., if we want to hash
-//   information X if CCACHE_A is set and information Y if CCACHE_B is set,
-//   there should never be a hash collision risk).
 void
-hash_delimiter(struct mdfour *md, const char *type)
+hash_delimiter(struct hash *hash, const char *type)
 {
-       hash_buffer(md, HASH_DELIMITER, sizeof(HASH_DELIMITER));
-       hash_buffer(md, type, strlen(type) + 1); // Include NUL.
+       do_hash_buffer(hash, HASH_DELIMITER, sizeof(HASH_DELIMITER));
+       do_hash_buffer(hash, type, strlen(type) + 1); // Include NUL.
+       do_debug_text(hash, "### ", 4);
+       do_debug_text(hash, type, strlen(type));
+       do_debug_text(hash, "\n", 1);
 }
 
 void
-hash_string(struct mdfour *md, const char *s)
+hash_string(struct hash *hash, const char *s)
 {
-       hash_string_length(md, s, strlen(s));
+       hash_string_buffer(hash, s, strlen(s));
 }
 
 void
-hash_string_length(struct mdfour *md, const char *s, int length)
+hash_string_buffer(struct hash *hash, const char *s, int length)
 {
-       hash_buffer(md, s, length);
+       hash_buffer(hash, s, length);
+       do_debug_text(hash, "\n", 1);
 }
 
 void
-hash_int(struct mdfour *md, int x)
+hash_int(struct hash *hash, int x)
 {
-       hash_buffer(md, (char *)&x, sizeof(x));
+       do_hash_buffer(hash, (char *)&x, sizeof(x));
+
+       char buf[16];
+       snprintf(buf, sizeof(buf), "%d", x);
+       do_debug_text(hash, buf, strlen(buf));
+       do_debug_text(hash, "\n", 1);
 }
 
-// Add contents of an open file to the hash. Returns true on success, otherwise
-// false.
 bool
-hash_fd(struct mdfour *md, int fd)
+hash_fd(struct hash *hash, int fd)
 {
        char buf[READ_BUFFER_SIZE];
        ssize_t n;
@@ -105,16 +165,15 @@ hash_fd(struct mdfour *md, int fd)
                        break;
                }
                if (n > 0) {
-                       hash_buffer(md, buf, n);
+                       do_hash_buffer(hash, buf, n);
+                       do_debug_text(hash, buf, n);
                }
        }
        return n == 0;
 }
 
-// Add contents of a file to the hash. Returns true on success, otherwise
-// false.
 bool
-hash_file(struct mdfour *md, const char *fname)
+hash_file(struct hash *hash, const char *fname)
 {
        int fd = open(fname, O_RDONLY|O_BINARY);
        if (fd == -1) {
@@ -122,7 +181,7 @@ hash_file(struct mdfour *md, const char *fname)
                return false;
        }
 
-       bool ret = hash_fd(md, fd);
+       bool ret = hash_fd(hash, fd);
        close(fd);
        return ret;
 }
diff --git a/src/hash.h b/src/hash.h
new file mode 100644 (file)
index 0000000..06a698a
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright (C) 2018 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef HASH_H
+#define HASH_H
+
+#include "system.h"
+
+struct hash;
+
+// Create a new hash.
+struct hash *hash_init(void);
+
+// Create a new hash from an existing hash state.
+struct hash *hash_copy(struct hash *hash);
+
+// Free a hash created by hash_init or hash_copy.
+void hash_free(struct hash *hash);
+
+// Enable debug logging of hashed input to a binary and a text file.
+void hash_enable_debug(
+       struct hash *hash, const char *section_name, FILE *debug_binary,
+       FILE *debug_text);
+
+// Return how many bytes have been hashed.
+size_t hash_input_size(struct hash *hash);
+
+// Return the hash result as a hex string. Caller frees.
+char *hash_result(struct hash *hash);
+
+// Return the hash result as 16 binary bytes.
+void hash_result_as_bytes(struct hash *hash, unsigned char *out);
+
+// Return whether hash1 and hash2 are equal.
+bool hash_equal(struct hash *hash1, struct hash *hash2);
+
+// Hash some data that is unlikely to occur in the input. The idea is twofold:
+//
+// - Delimit things like arguments from each other (e.g., so that -I -O2 and
+//   -I-O2 hash differently).
+// - Tag different types of hashed information so that it's possible to do
+//   conditional hashing of information in a safe way (e.g., if we want to hash
+//   information X if CCACHE_A is set and information Y if CCACHE_B is set,
+//   there should never be a hash collision risk).
+void hash_delimiter(struct hash *hash, const char *type);
+
+// Hash bytes in a buffer.
+//
+// If hash debugging is enabled, the bytes are written verbatim to the text
+// input file.
+void hash_buffer(struct hash *hash, const void *s, size_t len);
+
+// Hash a string.
+//
+// If hash debugging is enabled, the string is written to the text input file
+// followed by a newline.
+void hash_string(struct hash *hash, const char *s);
+
+// Hash a string with a known size.
+//
+// If hash debugging is enabled, the string is written to the text input file
+// followed by a newline.
+void hash_string_buffer(struct hash *hash, const char *s, int length);
+
+// Hash an integer.
+//
+// If hash debugging is enabled, the integer is written in text form to the
+// text input file followed by a newline.
+void hash_int(struct hash *hash, int x);
+
+// Add contents of an open file to the hash.
+//
+// If hash debugging is enabled, the data is written verbatim to the text input
+// file.
+//
+// Returns true on success, otherwise false.
+bool hash_fd(struct hash *hash, int fd);
+
+// Add contents of a file to the hash.
+//
+// If hash debugging is enabled, the data is written verbatim to the text input
+// file.
+//
+// Returns true on success, otherwise false.
+bool hash_file(struct hash *hash, const char *fname);
+
+#endif
index 02ab45427fadc890928e8e4b8583660b6e230c38..308e72cab81aa8a35be280ff8892c63bd64c2f19 100644 (file)
 */
 
 #include "hashtable.h"
+#define HASHTABLE_INDEXFOR
 #include "hashtable_private.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
 
+extern const unsigned int prime_table_length;
+extern const float max_load_factor;
+
 /*
 Credit for primes table: Aaron Krowne
  http://br.endernet.org/~akrowne/
@@ -51,7 +55,7 @@ static const unsigned int primes[] = {
 805306457, 1610612741
 };
 const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
-const float max_load_factor = 0.65;
+const float max_load_factor = 0.65f;
 
 /*****************************************************************************/
 struct hashtable *
@@ -77,7 +81,8 @@ create_hashtable(unsigned int minsize,
     h->entrycount   = 0;
     h->hashfn       = hashf;
     h->eqfn         = eqf;
-    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
+    double loadlimit_float = ceil((double)size * (double)max_load_factor);
+    h->loadlimit    = (unsigned int)loadlimit_float;
     return h;
 }
 
@@ -150,7 +155,8 @@ hashtable_expand(struct hashtable *h)
         }
     }
     h->tablelength = newsize;
-    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
+    double loadlimit_float = ceil((double)newsize* (double)max_load_factor);
+    h->loadlimit   = (unsigned int) loadlimit_float;
     return -1;
 }
 
index 428000752f7e22612e60f785b9afcac5e2b4d3f7..91fb387d8e8519ee0feee322bfee541c22053a94 100644 (file)
@@ -29,8 +29,8 @@
   POSSIBILITY OF SUCH DAMAGE.
 */
 
-#ifndef __HASHTABLE_CWC22_H__
-#define __HASHTABLE_CWC22_H__
+#ifndef HASHTABLE_CWC22_H
+#define HASHTABLE_CWC22_H
 
 #include "config.h"
 
@@ -194,7 +194,7 @@ hashtable_count(struct hashtable *h);
 void
 hashtable_destroy(struct hashtable *h, int free_values);
 
-#endif /* __HASHTABLE_CWC22_H__ */
+#endif /* HASHTABLE_CWC22_H */
 
 /*
  * Copyright (c) 2002, Christopher Clark
index 5dced841f31d447c83b1a73cdfa42d2fb1c271c9..1ee43da0c65451392732853c70deaff6242ae5df 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002, 2004 Christopher Clark  <firstname.lastname@cl.cam.ac.uk> */
 
 #include "hashtable.h"
+#define HASHTABLE_INDEXFOR
 #include "hashtable_private.h"
 #include "hashtable_itr.h"
 #include <stdlib.h> /* defines NULL */
index 9523b14a4b6bdf7801a0cba8b88955b701f58fd9..a0ac22cbca151c00de16e6ba1ba579894bf1d3c5 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
 
-#ifndef __HASHTABLE_ITR_CWC22__
-#define __HASHTABLE_ITR_CWC22__
+#ifndef HASHTABLE_ITR_CWC22_H
+#define HASHTABLE_ITR_CWC22_H
 #include "hashtable.h"
 #include "hashtable_private.h" /* needed to enable inlining */
 
@@ -86,7 +86,7 @@ int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \
 
 
 
-#endif /* __HASHTABLE_ITR_CWC22__*/
+#endif /* HASHTABLE_ITR_CWC22_H */
 
 /*
  * Copyright (c) 2002, 2004, Christopher Clark
index a81afca8843485fedaf72c40b39f9133bae9ea30..260afcab9197392e1ce16857bf3bfcf714598d94 100644 (file)
@@ -1,7 +1,7 @@
 /* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
 
-#ifndef __HASHTABLE_PRIVATE_CWC22_H__
-#define __HASHTABLE_PRIVATE_CWC22_H__
+#ifndef HASHTABLE_PRIVATE_CWC22_H
+#define HASHTABLE_PRIVATE_CWC22_H
 
 #include "hashtable.h"
 
@@ -28,6 +28,7 @@ unsigned int
 hash(struct hashtable *h, void *k);
 
 /*****************************************************************************/
+#ifdef HASHTABLE_INDEXFOR
 /* indexFor */
 static inline unsigned int
 indexFor(unsigned int tablelength, unsigned int hashvalue) {
@@ -41,6 +42,7 @@ indexFor(unsigned int tablelength, unsigned int hashvalue)
     return (hashvalue & (tablelength - 1u));
 }
 */
+#endif
 
 /*****************************************************************************/
 #define freekey(X) free(X)
@@ -49,7 +51,7 @@ indexFor(unsigned int tablelength, unsigned int hashvalue)
 
 /*****************************************************************************/
 
-#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+#endif /* HASHTABLE_PRIVATE_CWC22_H */
 
 /*
  * Copyright (c) 2002, Christopher Clark
index ddbd0daa742f636bec488e938393ea2cce191606..4ed10d774d2a8d425811fb4960d22db50019e223 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2009-2016 Joel Rosdahl
+// Copyright (C) 2009-2018 Joel Rosdahl
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by the Free
@@ -89,8 +89,8 @@ check_for_temporal_macros(const char *str, size_t len)
 // Hash a string. Returns a bitmask of HASH_SOURCE_CODE_* results.
 int
 hash_source_code_string(
-  struct conf *conf, struct mdfour *hash, const char *str, size_t len,
-  const char *path)
+       struct conf *conf, struct hash *hash, const char *str, size_t len,
+       const char *path)
 {
        int result = HASH_SOURCE_CODE_OK;
 
@@ -101,7 +101,7 @@ hash_source_code_string(
        }
 
        // Hash the source string.
-       hash_buffer(hash, str, len);
+       hash_string_buffer(hash, str, len);
 
        if (result & HASH_SOURCE_CODE_FOUND_DATE) {
                // Make sure that the hash sum changes if the (potential) expansion of
@@ -110,9 +110,9 @@ hash_source_code_string(
                struct tm *now = localtime(&t);
                cc_log("Found __DATE__ in %s", path);
                hash_delimiter(hash, "date");
-               hash_buffer(hash, &now->tm_year, sizeof(now->tm_year));
-               hash_buffer(hash, &now->tm_mon, sizeof(now->tm_mon));
-               hash_buffer(hash, &now->tm_mday, sizeof(now->tm_mday));
+               hash_int(hash, now->tm_year);
+               hash_int(hash, now->tm_mon);
+               hash_int(hash, now->tm_mday);
        }
        if (result & HASH_SOURCE_CODE_FOUND_TIME) {
                // We don't know for sure that the program actually uses the __TIME__
@@ -130,7 +130,7 @@ hash_source_code_string(
 // Hash a file ignoring comments. Returns a bitmask of HASH_SOURCE_CODE_*
 // results.
 int
-hash_source_code_file(struct conf *conf, struct mdfour *hash, const char *path)
+hash_source_code_file(struct conf *conf, struct hash *hash, const char *path)
 {
        if (is_precompiled_header(path)) {
                if (hash_file(hash, path)) {
@@ -151,7 +151,7 @@ hash_source_code_file(struct conf *conf, struct mdfour *hash, const char *path)
 }
 
 bool
-hash_command_output(struct mdfour *hash, const char *command,
+hash_command_output(struct hash *hash, const char *command,
                     const char *compiler)
 {
 #ifdef _WIN32
@@ -216,11 +216,11 @@ hash_command_output(struct mdfour *hash, const char *command,
                win32args = (char *)command;  // quoted
        }
        BOOL ret =
-         CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
+               CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
        CloseHandle(pipe_out[1]);
        args_free(args);
        free(win32args);
-       if (cmd) {
+       if (!cmd) {
                free((char *)command);  // Original argument was replaced above.
        }
        if (ret == 0) {
@@ -270,7 +270,8 @@ hash_command_output(struct mdfour *hash, const char *command,
                close(pipefd[1]);
                bool ok = hash_fd(hash, pipefd[0]);
                if (!ok) {
-                       cc_log("Error hashing compiler check command output: %s", strerror(errno));
+                       cc_log("Error hashing compiler check command output: %s",
+                              strerror(errno));
                        stats_update(STATS_COMPCHECK);
                }
                close(pipefd[0]);
@@ -291,7 +292,7 @@ hash_command_output(struct mdfour *hash, const char *command,
 }
 
 bool
-hash_multicommand_output(struct mdfour *hash, const char *commands,
+hash_multicommand_output(struct hash *hash, const char *commands,
                          const char *compiler)
 {
        char *command_string = x_strdup(commands);
index ae9abf19f190a974a08cd54211c3e2a1338317e0..b6b916efb6e009bff7bf6e0cb266868d8c3fec2d 100644 (file)
@@ -1,8 +1,24 @@
+// Copyright (C) 2009-2018 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
 #ifndef HASHUTIL_H
 #define HASHUTIL_H
 
 #include "conf.h"
-#include "mdfour.h"
+#include "hash.h"
 #include <inttypes.h>
 
 struct file_hash
@@ -23,13 +39,13 @@ int file_hashes_equal(struct file_hash *fh1, struct file_hash *fh2);
 
 int check_for_temporal_macros(const char *str, size_t len);
 int hash_source_code_string(
-       struct conf *conf, struct mdfour *hash, const char *str, size_t len,
+       struct conf *conf, struct hash *hash, const char *str, size_t len,
        const char *path);
 int hash_source_code_file(
-       struct conf *conf, struct mdfour *hash, const char *path);
-bool hash_command_output(struct mdfour *hash, const char *command,
+       struct conf *conf, struct hash *hash, const char *path);
+bool hash_command_output(struct hash *hash, const char *command,
                          const char *compiler);
-bool hash_multicommand_output(struct mdfour *hash, const char *command,
+bool hash_multicommand_output(struct hash *hash, const char *command,
                               const char *compiler);
 
 #endif
index 8d4321dc955194bb5f6f22a50227d2e87ea68650..4c4a998bc8461ac9fe2a385ff7a1dbd9dc9ddad1 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2010-2016 Joel Rosdahl
+// Copyright (C) 2010-2018 Joel Rosdahl
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by the Free
@@ -16,6 +16,8 @@
 
 #include "ccache.h"
 
+#include "language.h"
+
 // Supported file extensions and corresponding languages (as in parameter to
 // the -x option).
 static const struct {
@@ -174,5 +176,7 @@ language_is_supported(const char *language)
 bool
 language_is_preprocessed(const char *language)
 {
-       return str_eq(language, p_language_for_language(language));
+       const char *p_language = p_language_for_language(language);
+       assert(p_language);
+       return str_eq(language, p_language);
 }
index 02df219585037065b82de38af2ef964368998f4f..5e0bcac62520fd82879172476d54cf914a8bcddc 100644 (file)
@@ -67,7 +67,7 @@ static const uint32_t MAX_MANIFEST_ENTRIES = 100;
 static const uint32_t MAX_MANIFEST_FILE_INFO_ENTRIES = 10000;
 
 #define ccache_static_assert(e) \
-  do { enum { ccache_static_assert__ = 1/(e) }; } while (false)
+       do { enum { ccache_static_assert__ = 1/(e) }; } while (false)
 
 struct file_info {
        // Index to n_files.
@@ -155,7 +155,7 @@ free_manifest(struct manifest *mf)
 }
 
 #define READ_BYTE(var) \
-  do { \
+       do { \
                int ch_ = gzgetc(f); \
                if (ch_ == EOF) { \
                        goto error; \
@@ -164,7 +164,7 @@ free_manifest(struct manifest *mf)
        } while (false)
 
 #define READ_INT(size, var) \
-  do { \
+       do { \
                uint64_t u_ = 0; \
                for (size_t i_ = 0; i_ < (size); i_++) { \
                        int ch_ = gzgetc(f); \
@@ -178,7 +178,7 @@ free_manifest(struct manifest *mf)
        } while (false)
 
 #define READ_STR(var) \
-  do { \
+       do { \
                char buf_[1024]; \
                size_t i_; \
                for (i_ = 0; i_ < sizeof(buf_); i_++) { \
@@ -198,7 +198,7 @@ free_manifest(struct manifest *mf)
        } while (false)
 
 #define READ_BYTES(n, var) \
-  do { \
+       do { \
                for (size_t i_ = 0; i_ < (n); i_++) { \
                        int ch_ = gzgetc(f); \
                        if (ch_ == EOF) { \
@@ -271,8 +271,8 @@ read_manifest(gzFile f)
        for (uint32_t i = 0; i < mf->n_objects; i++) {
                READ_INT(4, mf->objects[i].n_file_info_indexes);
                mf->objects[i].file_info_indexes =
-                 x_calloc(mf->objects[i].n_file_info_indexes,
-                          sizeof(*mf->objects[i].file_info_indexes));
+                       x_calloc(mf->objects[i].n_file_info_indexes,
+                                sizeof(*mf->objects[i].file_info_indexes));
                for (uint32_t j = 0; j < mf->objects[i].n_file_info_indexes; j++) {
                        READ_INT(4, mf->objects[i].file_info_indexes[j]);
                }
@@ -289,7 +289,7 @@ error:
 }
 
 #define WRITE_INT(size, var) \
-  do { \
+       do { \
                uint64_t u_ = (var); \
                uint8_t ch_; \
                size_t i_; \
@@ -302,14 +302,14 @@ error:
        } while (false)
 
 #define WRITE_STR(var) \
-  do { \
+       do { \
                if (gzputs(f, var) == EOF || gzputc(f, '\0') == EOF) { \
                        goto error; \
                } \
        } while (false)
 
 #define WRITE_BYTES(n, var) \
-  do { \
+       do { \
                size_t i_; \
                for (i_ = 0; i_ < (n); i_++) { \
                        if (gzputc(f, (var)[i_]) == EOF) { \
@@ -383,7 +383,8 @@ verify_object(struct conf *conf, struct manifest *mf, struct object *obj,
 
                // Clang stores the mtime of the included files in the precompiled header,
                // and will error out if that header is later used without rebuilding.
-               if (guessed_compiler == GUESSED_CLANG
+               if ((guessed_compiler == GUESSED_CLANG
+                    || guessed_compiler == GUESSED_UNKNOWN)
                    && output_is_precompiled_header
                    && fi->mtime != st->mtime) {
                        cc_log("Precompiled header includes %s, which has a new mtime", path);
@@ -391,30 +392,41 @@ verify_object(struct conf *conf, struct manifest *mf, struct object *obj,
                }
 
                if (conf->sloppiness & SLOPPY_FILE_STAT_MATCHES) {
-                       if (fi->mtime == st->mtime && fi->ctime == st->ctime) {
-                               cc_log("mtime/ctime hit for %s", path);
-                               continue;
+                       if (!(conf->sloppiness & SLOPPY_FILE_STAT_MATCHES_CTIME)) {
+                               if (fi->mtime == st->mtime && fi->ctime == st->ctime) {
+                                       cc_log("mtime/ctime hit for %s", path);
+                                       continue;
+                               } else {
+                                       cc_log("mtime/ctime miss for %s", path);
+                               }
                        } else {
-                               cc_log("mtime/ctime miss for %s", path);
+                               if (fi->mtime == st->mtime) {
+                                       cc_log("mtime hit for %s", path);
+                                       continue;
+                               } else {
+                                       cc_log("mtime miss for %s", path);
+                               }
                        }
                }
 
                struct file_hash *actual = hashtable_search(hashed_files, path);
                if (!actual) {
-                       struct mdfour hash;
-                       hash_start(&hash);
-                       int result = hash_source_code_file(conf, &hash, path);
+                       struct hash *hash = hash_init();
+                       int result = hash_source_code_file(conf, hash, path);
                        if (result & HASH_SOURCE_CODE_ERROR) {
                                cc_log("Failed hashing %s", path);
+                               hash_free(hash);
                                return 0;
                        }
                        if (result & HASH_SOURCE_CODE_FOUND_TIME) {
+                               hash_free(hash);
                                return 0;
                        }
                        actual = x_malloc(sizeof(*actual));
-                       hash_result_as_bytes(&hash, actual->hash);
-                       actual->size = hash.totalN;
+                       hash_result_as_bytes(hash, actual->hash);
+                       actual->size = hash_input_size(hash);
                        hashtable_insert(hashed_files, x_strdup(path), actual);
+                       hash_free(hash);
                }
                if (memcmp(fi->hash, actual->hash, mf->hash_size) != 0
                    || fi->size != actual->size) {
@@ -429,7 +441,7 @@ static struct hashtable *
 create_string_index_map(char **strings, uint32_t len)
 {
        struct hashtable *h =
-         create_hashtable(1000, hash_from_string, strings_equal);
+               create_hashtable(1000, hash_from_string, strings_equal);
        for (uint32_t i = 0; i < len; i++) {
                uint32_t *index = x_malloc(sizeof(*index));
                *index = i;
@@ -442,7 +454,7 @@ static struct hashtable *
 create_file_info_index_map(struct file_info *infos, uint32_t len)
 {
        struct hashtable *h =
-         create_hashtable(1000, hash_from_file_info, file_infos_equal);
+               create_hashtable(1000, hash_from_file_info, file_infos_equal);
        for (uint32_t i = 0; i < len; i++) {
                struct file_info *fi = x_malloc(sizeof(*fi));
                *fi = infos[i];
@@ -520,10 +532,10 @@ add_file_info_indexes(uint32_t *indexes, uint32_t size,
 
        // path --> index
        struct hashtable *mf_files =
-         create_string_index_map(mf->files, mf->n_files);
+               create_string_index_map(mf->files, mf->n_files);
        // struct file_info --> index
        struct hashtable *mf_file_infos =
-         create_file_info_index_map(mf->file_infos, mf->n_file_infos);
+               create_file_info_index_map(mf->file_infos, mf->n_file_infos);
        struct hashtable_itr *iter = hashtable_iterator(included_files);
        uint32_t i = 0;
        do {
index f557a20fb8322124b1e0d06ecfa1579bc96af671..11e0fba1ef5f910f5c237f316401c9a9fdfbeccb 100644 (file)
 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 #include "ccache.h"
+#include "mdfour.h"
 
 // NOTE: This code makes no attempt to be fast!
 
-static struct mdfour *m;
-
 #define MASK32 (0xffffffff)
 
 #define F(X, Y, Z) ((((X)&(Y)) | ((~(X))&(Z))))
@@ -29,23 +28,23 @@ static struct mdfour *m;
 #define lshift(x, s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32)))
 
 #define ROUND1(a, b, c, d, k, s) \
-  a = lshift((a + F(b, c, d) + M[k])&MASK32, s)
+       a = lshift((a + F(b, c, d) + M[k])&MASK32, s)
 #define ROUND2(a, b, c, d, k, s) \
-  a = lshift((a + G(b, c, d) + M[k] + 0x5A827999)&MASK32, s)
+       a = lshift((a + G(b, c, d) + M[k] + 0x5A827999)&MASK32, s)
 #define ROUND3(a, b, c, d, k, s) \
-  a = lshift((a + H(b, c, d) + M[k] + 0x6ED9EBA1)&MASK32, s)
+       a = lshift((a + H(b, c, d) + M[k] + 0x6ED9EBA1)&MASK32, s)
 
 // This applies md4 to 64 byte chunks.
 static void
-mdfour64(uint32_t *M)
+mdfour64(struct mdfour *md, uint32_t *M)
 {
        uint32_t AA, BB, CC, DD;
        uint32_t A, B, C, D;
 
-       A = m->A;
-       B = m->B;
-       C = m->C;
-       D = m->D;
+       A = md->A;
+       B = md->B;
+       C = md->C;
+       D = md->D;
        AA = A;
        BB = B;
        CC = C;
@@ -89,10 +88,10 @@ mdfour64(uint32_t *M)
        C &= MASK32;
        D &= MASK32;
 
-       m->A = A;
-       m->B = B;
-       m->C = C;
-       m->D = D;
+       md->A = A;
+       md->B = B;
+       md->C = C;
+       md->D = D;
 }
 
 static void
@@ -134,10 +133,10 @@ mdfour_begin(struct mdfour *md)
 }
 
 static
-void mdfour_tail(const unsigned char *in, size_t n)
+void mdfour_tail(struct mdfour *md, const unsigned char *in, size_t n)
 {
-       m->totalN += n;
-       uint32_t b = m->totalN * 8;
+       md->totalN += n;
+       uint32_t b = md->totalN * 8;
        unsigned char buf[128] = { 0 };
        uint32_t M[16];
        if (n) {
@@ -148,32 +147,22 @@ void mdfour_tail(const unsigned char *in, size_t n)
        if (n <= 55) {
                copy4(buf+56, b);
                copy64(M, buf);
-               mdfour64(M);
+               mdfour64(md, M);
        } else {
                copy4(buf+120, b);
                copy64(M, buf);
-               mdfour64(M);
+               mdfour64(md, M);
                copy64(M, buf+64);
-               mdfour64(M);
+               mdfour64(md, M);
        }
 }
 
 void
 mdfour_update(struct mdfour *md, const unsigned char *in, size_t n)
 {
-#ifdef CCACHE_DEBUG_HASH
-       if (n > 0 && getenv("CCACHE_DEBUG_HASH")) {
-               FILE *f = fopen("ccache-debug-hash.bin", "a");
-               fwrite(in, 1, n, f);
-               fclose(f);
-       }
-#endif
-
-       m = md;
-
        if (!in) {
                if (!md->finalized) {
-                       mdfour_tail(md->tail, md->tail_len);
+                       mdfour_tail(md, md->tail, md->tail_len);
                        md->finalized = 1;
                }
                return;
@@ -191,18 +180,18 @@ mdfour_update(struct mdfour *md, const unsigned char *in, size_t n)
                in += len;
                if (md->tail_len == 64) {
                        copy64(M, md->tail);
-                       mdfour64(M);
-                       m->totalN += 64;
+                       mdfour64(md, M);
+                       md->totalN += 64;
                        md->tail_len = 0;
                }
        }
 
        while (n >= 64) {
                copy64(M, in);
-               mdfour64(M);
+               mdfour64(md, M);
                in += 64;
                n -= 64;
-               m->totalN += 64;
+               md->totalN += 64;
        }
 
        if (n) {
index b935ee930e34dfb5bf30bbcd6e5d600c25612042..e4cdadea57aadcd5c4f36aa44d6e8b2c1d8bb8c3 100644 (file)
 #include <config.h>
 #endif /* HAVE_CONFIG_H */
 
-#if TEST_SNPRINTF
+#ifdef TEST_SNPRINTF
 #include <math.h>      /* For pow(3), NAN, and INFINITY. */
 #include <string.h>    /* For strcmp(3). */
 #if defined(__NetBSD__) || \
@@ -1202,7 +1202,7 @@ again:
         * Factor of ten with the number of digits needed for the fractional
         * part.  For example, if the precision is 3, the mask will be 1000.
         */
-       mask = mypow10(precision);
+       mask = (UINTMAX_T)mypow10(precision);
        /*
         * We "cheat" by converting the fractional part to integer by
         * multiplying by a factor of ten.
@@ -1454,7 +1454,7 @@ cast(LDOUBLE value)
        if (value >= UINTMAX_MAX)
                return UINTMAX_MAX;
 
-       result = value;
+       result = (UINTMAX_T)value;
        /*
         * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to
         * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates
@@ -1574,7 +1574,7 @@ rpl_asprintf(va_alist) va_dcl
 int main(void);
 #endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */
 
-#if TEST_SNPRINTF
+#ifdef TEST_SNPRINTF
 int
 main(void)
 {
index 5ac56fdc229aff2d5bd4a27abcbb07cea92f9b36..ef6a2914ede5a49ab43a4ea54c8035119a1e24a3 100644 (file)
@@ -41,15 +41,26 @@ static struct counters *counter_updates;
 #define FLAG_ALWAYS 2 // always show, even if zero
 #define FLAG_NEVER 4 // never show
 
-static void display_size_times_1024(uint64_t size);
+// Returns a formatted version of a statistics value, or NULL if the statistics
+// line shouldn't be printed. Caller frees.
+typedef char *format_fn(uint64_t value);
+
+static format_fn format_size_times_1024;
+static format_fn format_timestamp;
 
 // Statistics fields in display order.
 static struct {
        enum stats stat;
        char *message;
-       void (*fn)(uint64_t);
+       format_fn *format_fn; // NULL -> use plain integer format
        unsigned flags;
 } stats_info[] = {
+       {
+               STATS_ZEROTIMESTAMP,
+               "stats zeroed",
+               format_timestamp,
+               FLAG_ALWAYS
+       },
        {
                STATS_CACHEHIT_DIR,
                "cache hit (direct)",
@@ -215,7 +226,7 @@ static struct {
        {
                STATS_TOTALSIZE,
                "cache size",
-               display_size_times_1024,
+               format_size_times_1024,
                FLAG_NOZERO|FLAG_ALWAYS
        },
        {
@@ -230,12 +241,6 @@ static struct {
                NULL,
                FLAG_NOZERO|FLAG_NEVER
        },
-       {
-               STATS_ZEROTIMESTAMP,
-               "stats last zeroed at",
-               NULL,
-               FLAG_NEVER
-       },
        {
                STATS_NONE,
                NULL,
@@ -244,18 +249,31 @@ static struct {
        }
 };
 
-static void
-display_size(uint64_t size)
+static char *
+format_size(uint64_t size)
 {
        char *s = format_human_readable_size(size);
-       printf("%11s", s);
-       free(s);
+       reformat(&s, "%11s", s);
+       return s;
 }
 
-static void
-display_size_times_1024(uint64_t size)
+static char *
+format_size_times_1024(uint64_t size)
 {
-       display_size(size * 1024);
+       return format_size(size * 1024);
+}
+
+static char *
+format_timestamp(uint64_t timestamp)
+{
+       if (timestamp > 0) {
+               struct tm *tm = localtime((time_t *)&timestamp);
+               char buffer[100];
+               strftime(buffer, sizeof(buffer), "%c", tm);
+               return format("    %s", buffer);
+       } else {
+               return NULL;
+       }
 }
 
 // Parse a stats file from a buffer, adding to the counters.
@@ -283,13 +301,6 @@ parse_stats(struct counters *counters, const char *buf)
 void
 stats_write(const char *path, struct counters *counters)
 {
-       struct stat st;
-       if (stat(path, &st) != 0 && errno == ENOENT) {
-               // New stats, update zero timestamp.
-               time_t now;
-               time(&now);
-               stats_timestamp(now, counters);
-       }
        char *tmp_file = format("%s.tmp", path);
        FILE *f = create_tmp_file(&tmp_file, "wb");
        for (size_t i = 0; i < counters->size; i++) {
@@ -331,13 +342,6 @@ stats_read(const char *sfile, struct counters *counters)
        free(data);
 }
 
-// Set the timestamp when the counters were last zeroed out.
-void
-stats_timestamp(time_t time, struct counters *counters)
-{
-       counters->data[STATS_ZEROTIMESTAMP] = (unsigned) time;
-}
-
 // Write counter updates in counter_updates to disk.
 void
 stats_flush(void)
@@ -385,7 +389,7 @@ stats_flush(void)
        stats_write(stats_file, counters);
        lockfile_release(stats_file);
 
-       if (!str_eq(conf->log_file, "")) {
+       if (!str_eq(conf->log_file, "") || conf->debug) {
                for (int i = 0; i < STATS_END; ++i) {
                        if (counter_updates->data[stats_info[i].stat] != 0
                            && !(stats_info[i].flags & FLAG_NOZERO)) {
@@ -441,10 +445,12 @@ stats_get_pending(enum stats stat)
 
 // Sum and display the total stats for all cache dirs.
 void
-stats_summary(struct conf *conf)
+stats_summary(void)
 {
        struct counters *counters = counters_init(STATS_END);
-       time_t oldest = 0;
+       time_t updated = 0;
+       struct stat st;
+       unsigned zero_timestamp = 0;
 
        assert(conf);
 
@@ -460,23 +466,25 @@ stats_summary(struct conf *conf)
 
                counters->data[STATS_ZEROTIMESTAMP] = 0; // Don't add
                stats_read(fname, counters);
-               time_t current = (time_t) counters->data[STATS_ZEROTIMESTAMP];
-               if (current != 0 && (oldest == 0 || current < oldest)) {
-                       oldest = current;
+               zero_timestamp = MAX(counters->data[STATS_ZEROTIMESTAMP], zero_timestamp);
+               if (stat(fname, &st) == 0 && st.st_mtime > updated) {
+                       updated = st.st_mtime;
                }
                free(fname);
        }
 
+       counters->data[STATS_ZEROTIMESTAMP] = zero_timestamp;
+
        printf("cache directory                     %s\n", conf->cache_dir);
        printf("primary config                      %s\n",
               primary_config_path ? primary_config_path : "");
        printf("secondary config      (readonly)    %s\n",
               secondary_config_path ? secondary_config_path : "");
-       if (oldest) {
-               struct tm *tm = localtime(&oldest);
+       if (updated) {
+               struct tm *tm = localtime(&updated);
                char timestamp[100];
                strftime(timestamp, sizeof(timestamp), "%c", tm);
-               printf("stats zero time                     %s\n", timestamp);
+               printf("stats updated                       %s\n", timestamp);
        }
 
        // ...and display them.
@@ -490,12 +498,15 @@ stats_summary(struct conf *conf)
                        continue;
                }
 
-               printf("%-31s ", stats_info[i].message);
-               if (stats_info[i].fn) {
-                       stats_info[i].fn(counters->data[stat]);
-                       printf("\n");
+               char *value;
+               if (stats_info[i].format_fn) {
+                       value = stats_info[i].format_fn(counters->data[stat]);
                } else {
-                       printf("%8u\n", counters->data[stat]);
+                       value = format("%8u", counters->data[stat]);
+               }
+               if (value) {
+                       printf("%-31s %s\n", stats_info[i].message, value);
+                       free(value);
                }
 
                if (stat == STATS_TOCACHE) {
@@ -513,9 +524,9 @@ stats_summary(struct conf *conf)
                printf("max files                       %8u\n", conf->max_files);
        }
        if (conf->max_size != 0) {
-               printf("max cache size                  ");
-               display_size(conf->max_size);
-               printf("\n");
+               char *value = format_size(conf->max_size);
+               printf("max cache size                  %s\n", value);
+               free(value);
        }
 
        counters_free(counters);
@@ -531,6 +542,8 @@ stats_zero(void)
        x_unlink(fname);
        free(fname);
 
+       time_t timestamp = time(NULL);
+
        for (int dir = 0; dir <= 0xF; dir++) {
                struct counters *counters = counters_init(STATS_END);
                struct stat st;
@@ -547,7 +560,7 @@ stats_zero(void)
                                        counters->data[stats_info[i].stat] = 0;
                                }
                        }
-                       stats_timestamp(time(NULL), counters);
+                       counters->data[STATS_ZEROTIMESTAMP] = timestamp;
                        stats_write(fname, counters);
                        lockfile_release(fname);
                }
index 53c3a0faaccc5997262cc9cba89de956598825c9..8cb69fc711de3cdff317d8eacf9179f7ee87e709 100644 (file)
@@ -1,5 +1,5 @@
 // Copyright (C) 2002 Andrew Tridgell
-// Copyright (C) 2009-2017 Joel Rosdahl
+// Copyright (C) 2009-2018 Joel Rosdahl
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by the Free
@@ -28,6 +28,7 @@
 // compiler (for example, inline assembly systems).
 
 #include "ccache.h"
+#include "hash.h"
 
 static bool print_unified = true;
 
@@ -102,7 +103,7 @@ build_table(void)
 
 // Buffer up characters before hashing them.
 static void
-pushchar(struct mdfour *hash, unsigned char c)
+pushchar(struct hash *hash, unsigned char c)
 {
        static unsigned char buf[64];
        static size_t len;
@@ -131,11 +132,11 @@ pushchar(struct mdfour *hash, unsigned char c)
 
 // Hash some C/C++ code after unifying.
 static void
-unify(struct mdfour *hash, unsigned char *p, size_t size)
+unify(struct hash *hash, unsigned char *p, size_t size)
 {
        build_table();
 
-       for (size_t ofs = 0; ofs < size; ) {
+       for (size_t ofs = 0; ofs < size;) {
                if (p[ofs] == '#') {
                        if ((size-ofs) > 2 && p[ofs+1] == ' ' && isdigit(p[ofs+2])) {
                                do {
@@ -218,8 +219,8 @@ unify(struct mdfour *hash, unsigned char *p, size_t size)
                        unsigned char q = p[ofs];
                        int i;
                        for (i = 0; i < tokens[q].num_toks; i++) {
-                               unsigned char *s = (unsigned char *)tokens[q].toks[i];
-                               int len = strlen((char *)s);
+                               const unsigned char *s = (const unsigned char *)tokens[q].toks[i];
+                               int len = strlen((const char *)s);
                                if (size >= ofs+len && memcmp(&p[ofs], s, len) == 0) {
                                        int j;
                                        for (j = 0; s[j]; j++) {
@@ -246,7 +247,7 @@ unify(struct mdfour *hash, unsigned char *p, size_t size)
 // Hash a file that consists of preprocessor output, but remove any line number
 // information from the hash.
 int
-unify_hash(struct mdfour *hash, const char *fname, bool debug)
+unify_hash(struct hash *hash, const char *fname, bool debug)
 {
        char *data;
        size_t size;
diff --git a/src/unify.h b/src/unify.h
new file mode 100644 (file)
index 0000000..eac167d
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 Joel Rosdahl
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef UNIFY_H
+#define UNIFY_H
+
+#include "hash.h"
+
+int unify_hash(struct hash *hash, const char *fname, bool print);
+
+#endif
index dcb8f658ecbd6231bbbd2967cc22a1fda0e625f7..3a34e33b0ed63bfc2fe43bb37ce81d5c9291f865 100644 (file)
 #endif
 
 static FILE *logfile;
+static char *logbuffer;
+static size_t logbufsize;
+static size_t logsize;
+
+#define LOGBUFSIZ 1024
 
 static bool
 init_log(void)
 {
        extern struct conf *conf;
 
-       if (logfile) {
+       if (logbuffer || logfile) {
                return true;
        }
        assert(conf);
+       if (conf->debug) {
+               logbufsize = LOGBUFSIZ;
+               logbuffer = x_malloc(logbufsize);
+               logsize = 0;
+       }
        if (str_eq(conf->log_file, "")) {
-               return false;
+               return conf->debug;
        }
        logfile = fopen(conf->log_file, "a");
        if (logfile) {
@@ -58,12 +68,23 @@ init_log(void)
        }
 }
 
+static void
+append_log(const char *s, size_t len)
+{
+       assert(logbuffer);
+       if (logsize + len + 1 > logbufsize) {
+               logbufsize = logbufsize + len + 1 + LOGBUFSIZ;
+               logbuffer = x_realloc(logbuffer, logbufsize);
+       }
+       memcpy(logbuffer + logsize, s, len);
+       logsize += len;
+}
+
 static void
 log_prefix(bool log_updated_time)
 {
-#ifdef HAVE_GETTIMEOFDAY
        static char prefix[200];
-
+#ifdef HAVE_GETTIMEOFDAY
        if (log_updated_time) {
                char timestamp[100];
                struct tm *tm;
@@ -78,10 +99,15 @@ log_prefix(bool log_updated_time)
                snprintf(prefix, sizeof(prefix),
                         "[%s.%06d %-5d] ", timestamp, (int)tv.tv_usec, (int)getpid());
        }
-       fputs(prefix, logfile);
 #else
-       fprintf(logfile, "[%-5d] ", (int)getpid());
+       snprintf(prefix, sizeof(prefix), "[%-5d] ", (int)getpid());
 #endif
+       if (logfile) {
+               fputs(prefix, logfile);
+       }
+       if (logbuffer) {
+               append_log(prefix, strlen(prefix));
+       }
 }
 
 static long
@@ -99,6 +125,8 @@ path_max(const char *path)
 #endif
 }
 
+static void warn_log_fail(void) ATTR_NORETURN;
+
 // Warn about failure writing to the log file and then exit.
 static void
 warn_log_fail(void)
@@ -118,12 +146,23 @@ vlog(const char *format, va_list ap, bool log_updated_time)
                return;
        }
 
+       va_list aq;
+       va_copy(aq, ap);
        log_prefix(log_updated_time);
-       int rc1 = vfprintf(logfile, format, ap);
-       int rc2 = fprintf(logfile, "\n");
-       if (rc1 < 0 || rc2 < 0) {
-               warn_log_fail();
+       if (logfile) {
+               int rc1 = vfprintf(logfile, format, ap);
+               int rc2 = fprintf(logfile, "\n");
+               if (rc1 < 0 || rc2 < 0) {
+                       warn_log_fail();
+               }
+       }
+       if (logbuffer) {
+               char buf[1024];
+               size_t len = vsnprintf(buf, sizeof(buf), format, aq);
+               append_log(buf, len);
+               append_log("\n", 1);
        }
+       va_end(aq);
 }
 
 // Write a message to the log file (adding a newline) and flush.
@@ -159,14 +198,32 @@ cc_log_argv(const char *prefix, char **argv)
        }
 
        log_prefix(true);
-       fputs(prefix, logfile);
-       print_command(logfile, argv);
-       int rc = fflush(logfile);
-       if (rc) {
-               warn_log_fail();
+       if (logfile) {
+               fputs(prefix, logfile);
+               print_command(logfile, argv);
+               int rc = fflush(logfile);
+               if (rc) {
+                       warn_log_fail();
+               }
+       }
+       if (logbuffer) {
+               append_log(prefix, strlen(prefix));
+               char *s = format_command(argv);
+               append_log(s, strlen(s));
+               free(s);
        }
 }
 
+// Copy the current log memory buffer to an output file.
+bool
+cc_dump_log_buffer(const char *path)
+{
+       FILE *file = fopen(path, "w");
+       fwrite(logbuffer, 1, logsize, file);
+       fclose(file);
+       return true;
+}
+
 // Something went badly wrong!
 void
 fatal(const char *format, ...)
@@ -216,7 +273,14 @@ copy_fd(int fd_in, int fd_out)
 int
 mkstemp(char *template)
 {
+#ifdef __GNUC__
+       #pragma GCC diagnostic push
+       #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
        mktemp(template);
+#ifdef __GNUC__
+       #pragma GCC diagnostic pop
+#endif
        return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
 }
 #endif
@@ -523,16 +587,16 @@ get_hostname(void)
                DWORD dw = WSAGetLastError();
 
                FormatMessage(
-                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                 FORMAT_MESSAGE_FROM_SYSTEM |
-                 FORMAT_MESSAGE_IGNORE_INSERTS,
-                 NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                 (LPTSTR) &lp_msg_buf, 0, NULL);
+                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                       (LPTSTR) &lp_msg_buf, 0, NULL);
 
                LPVOID lp_display_buf = (LPVOID) LocalAlloc(
-                 LMEM_ZEROINIT,
-                 (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 200)
-                 * sizeof(TCHAR));
+                       LMEM_ZEROINIT,
+                       (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 200)
+                       * sizeof(TCHAR));
                _snprintf((LPTSTR) lp_display_buf,
                          LocalSize(lp_display_buf) / sizeof(TCHAR),
                          TEXT("%s failed with error %lu: %s"), __FILE__, dw,
@@ -578,11 +642,11 @@ format_hash_as_string(const unsigned char *hash, int size)
        return ret;
 }
 
-char const CACHEDIR_TAG[] =
-  "Signature: 8a477f597d28d172789f06886806bc55\n"
-  "# This file is a cache directory tag created by ccache.\n"
-  "# For information about cache directory tags, see:\n"
-  "#\thttp://www.brynosaurus.com/cachedir/\n";
+static char const CACHEDIR_TAG[] =
+       "Signature: 8a477f597d28d172789f06886806bc55\n"
+       "# This file is a cache directory tag created by ccache.\n"
+       "# For information about cache directory tags, see:\n"
+       "#\thttp://www.brynosaurus.com/cachedir/\n";
 
 int
 create_cachedirtag(const char *dir)
@@ -775,9 +839,6 @@ reformat(char **ptr, const char *format, ...)
        }
        va_end(ap);
 
-       if (!ptr) {
-               fatal("Out of memory in reformat");
-       }
        if (saved) {
                free(saved);
        }
@@ -983,7 +1044,7 @@ parse_size_with_suffix(const char *str, uint64_t *size)
                // Default suffix: G.
                x *= 1000 * 1000 * 1000;
        }
-       *size = x;
+       *size = (uint64_t)x;
        return true;
 }
 
@@ -1006,7 +1067,7 @@ static BOOL GetFileNameFromHandle(HANDLE file_handle, TCHAR *filename,
 
        // Create a file mapping object.
        HANDLE file_map =
-         CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 1, NULL);
+               CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 1, NULL);
        if (!file_map) {
                return FALSE;
        }
@@ -1084,8 +1145,8 @@ x_realpath(const char *path)
                path++;  // Skip leading slash.
        }
        HANDLE path_handle = CreateFile(
-         path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
-         FILE_ATTRIBUTE_NORMAL, NULL);
+               path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+               FILE_ATTRIBUTE_NORMAL, NULL);
        if (INVALID_HANDLE_VALUE != path_handle) {
 #ifdef HAVE_GETFINALPATHNAMEBYHANDLEW
                GetFinalPathNameByHandle(path_handle, ret, maxlen, FILE_NAME_NORMALIZED);
@@ -1431,18 +1492,18 @@ x_rename(const char *oldpath, const char *newpath)
                LPVOID lp_msg_buf;
                DWORD dw = GetLastError();
                FormatMessage(
-                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                 FORMAT_MESSAGE_FROM_SYSTEM |
-                 FORMAT_MESSAGE_IGNORE_INSERTS,
-                 NULL, dw,
-                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lp_msg_buf,
-                 0,
-                 NULL);
+                       FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL, dw,
+                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lp_msg_buf,
+                       0,
+                       NULL);
 
                LPVOID lp_display_buf = (LPVOID) LocalAlloc(
-                 LMEM_ZEROINIT,
-                 (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 40)
-                 * sizeof(TCHAR));
+                       LMEM_ZEROINIT,
+                       (lstrlen((LPCTSTR) lp_msg_buf) + lstrlen((LPCTSTR) __FILE__) + 40)
+                       * sizeof(TCHAR));
                _snprintf((LPTSTR) lp_display_buf,
                          LocalSize(lp_display_buf) / sizeof(TCHAR),
                          TEXT("%s failed with error %lu: %s"), __FILE__, dw,
index 4d890db7e87e06c19fde5f5bc62e8afa7f0f0559..1f3d93a4c9d81a5e7b94ac36b2820bbdae1bb394 100644 (file)
@@ -1 +1 @@
-const char CCACHE_VERSION[] = "3.4.3";
+extern const char CCACHE_VERSION[]; const char CCACHE_VERSION[] = "3.5";
index 990a4d2514933709883a7d949ed52146675fe2c1..6378d468a258b134420c2434f62de8f0d3fb42ea 100644 (file)
@@ -39,7 +39,7 @@
 #  include <io.h>
 #endif
 
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32)
 #  define WIDECHAR
 #endif
 
index f09cdaf1e0543de911d8220befdb51fa8632a9e6..49dfcece0e1f9a5ccf5298a633045a7bcfb1bf25 100644 (file)
@@ -1893,7 +1893,7 @@ ZEXTERN int            ZEXPORT inflateValidate OF((z_streamp, int));
 ZEXTERN unsigned long  ZEXPORT inflateCodesUsed OF ((z_streamp));
 ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
 ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
-#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)
+#if defined(_WIN32) && !defined(Z_SOLO)
 ZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,
                                             const char *mode));
 #endif
index b079ea6a80f5abd23a6b2451d6eaee50ceda969b..3f0bc2de4a37331854009f940b0ea6e0677ed17e 100644 (file)
@@ -147,7 +147,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
 #  define OS_CODE 13
 #endif
 
-#if defined(WIN32) && !defined(__CYGWIN__)
+#if defined(WIN32)
 #  define OS_CODE  10
 #endif
 
index 82a80541049bca92f58c656ccc197fdc59c6d09b..0aac132a792a3f5476ba014ab0d8f729a3e0f897 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -158,6 +158,11 @@ expect_equal_object_files() {
             test_failed "Please install elfutils to get eu-elfcmp"
         fi
         eu-elfcmp -q "$1" "$2"
+    elif $HOST_OS_FREEBSD && $COMPILER_TYPE_CLANG; then
+        elfdump -a -w "$1".dump "$1"
+        elfdump -a -w "$2".dump "$2"
+        # these were the elfdump fields that seemed to differ (empirically)
+        diff -I e_shoff -I sh_size -I st_name "$1".dump "$2".dump > /dev/null
     else
         cmp -s "$1" "$2"
     fi
@@ -267,7 +272,7 @@ fi
 HOST_CCACHE_DIRS="/usr/lib/ccache/bin
 /usr/lib/ccache"
 for HOST_CCACHE_DIR in $HOST_CCACHE_DIRS; do
-    PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$HOST_CCACHE_DIR'"' | sed 's/:$//')
+    PATH="$(echo "$PATH:" | awk -v RS=: -v ORS=: '$0 != "'$HOST_CCACHE_DIR'"' | sed 's/:*$//')"
 done
 export PATH
 
@@ -288,6 +293,7 @@ COMPILER_USES_MINGW=false
 
 HOST_OS_APPLE=false
 HOST_OS_LINUX=false
+HOST_OS_FREEBSD=false
 HOST_OS_WINDOWS=false
 
 compiler_version="`$COMPILER --version 2>&1 | head -1`"
@@ -323,6 +329,9 @@ case $(uname -s) in
     *Linux*)
         HOST_OS_LINUX=true
         ;;
+    *FreeBSD*)
+        HOST_OS_FREEBSD=true
+        ;;
 esac
 
 if $HOST_OS_WINDOWS; then
@@ -364,6 +373,7 @@ nocpp2
 cpp1
 multi_arch
 serialize_diagnostics
+sanitize_blacklist
 debug_prefix_map
 masquerading
 hardlink
index 307100e84d3888519e20230370186e8f187450b8..63ef9e7145da5d46b4cd69e686848e2cab7a3084 100644 (file)
@@ -298,8 +298,8 @@ base_tests() {
     # -------------------------------------------------------------------------
     TEST "CCACHE_EXTRAFILES"
 
-    echo a >a
-    echo b >b
+    echo "a" >a
+    echo "b" >b
 
     $CCACHE_COMPILE -c test1.c
     expect_stat 'cache hit (preprocessed)' 0
@@ -495,7 +495,8 @@ EOF
 
     cat >compiler.sh <<EOF
 #!/bin/sh
-export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+export CCACHE_DISABLE
 exec $COMPILER "\$@"
 # A comment
 EOF
@@ -523,7 +524,8 @@ EOF
 
     cat >compiler.sh <<EOF
 #!/bin/sh
-export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+export CCACHE_DISABLE
 exec $COMPILER "\$@"
 EOF
     chmod +x compiler.sh
@@ -546,7 +548,8 @@ EOF
 
     cat >compiler.sh <<EOF
 #!/bin/sh
-export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+export CCACHE_DISABLE
 exec $COMPILER "\$@"
 EOF
     chmod +x compiler.sh
@@ -569,7 +572,8 @@ EOF
 
     cat >compiler.sh <<EOF
 #!/bin/sh
-export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+export CCACHE_DISABLE
 exec $COMPILER "\$@"
 EOF
     chmod +x compiler.sh
@@ -595,7 +599,8 @@ EOF
 
     cat >compiler.sh <<EOF
 #!/bin/sh
-export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+export CCACHE_DISABLE
 exec $COMPILER "\$@"
 EOF
     chmod +x compiler.sh
@@ -628,7 +633,8 @@ EOF
 
     cat >compiler.sh <<EOF
 #!/bin/sh
-export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+export CCACHE_DISABLE
 exec $COMPILER "\$@"
 EOF
     chmod +x compiler.sh
@@ -787,7 +793,8 @@ EOF
 
     cat >buggy-cpp <<EOF
 #!/bin/sh
-export CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+CCACHE_DISABLE=1 # If $COMPILER happens to be a ccache symlink...
+export CCACHE_DISABLE
 if echo "\$*" | grep -- -D >/dev/null; then
   $COMPILER "\$@"
 else
@@ -913,6 +920,20 @@ EOF
             test_failed "boolean env var '$invalid_val' should be rejected"
         fi
     done
+
+    # -------------------------------------------------------------------------
+    TEST "--hash-file"
+
+    >empty
+    $CCACHE --hash-file empty > hash.out
+    printf "a" | $CCACHE --hash-file - >> hash.out
+
+    if grep '31d6cfe0d16ae931b73c59d7e0c089c0-0' hash.out >/dev/null 2>&1 && \
+       grep 'bde52cb31de33e46245e05fbdbd6fb24-1' hash.out >/dev/null 2>&1; then
+        : OK
+    else
+        test_failed "Unexpected output of --hash-file"
+    fi
 }
 
 # =============================================================================
index 965d46678425d2c16480cd3aa785dc7ccb9754f2..6655778dfe3aa6e093e856a94f7696632fae7e3d 100644 (file)
@@ -33,7 +33,7 @@ SUITE_cpp1() {
     elif $COMPILER_TYPE_CLANG; then
         cpp_flag="-frewrite-includes"
     fi
-    cpp_flag+=" -DBAZ=3"
+    cpp_flag="$cpp_flag -DBAZ=3"
 
     # -------------------------------------------------------------------------
     TEST "Base case"
index 25cc36ff2248a4e5143c0d1de3912cf764babd8d..d00e654767c14b233a4cb53632af21d4fac9a7bd 100644 (file)
@@ -23,6 +23,8 @@ EOF
 objdump_cmd() {
     if $HOST_OS_APPLE; then
         xcrun dwarfdump -r0 $1
+    elif $HOST_OS_FREEBSD; then
+        objdump -W $1
     else
         objdump -g $1
     fi
index 085029c090c73c050727421dadb344c071b8aa51..f12d6c481fd3bc04f759755442bf2b322e340608 100644 (file)
@@ -448,7 +448,7 @@ EOF
     expect_stat 'cache miss' 1
     expect_equal_files test.d expected.d
 
-    find $CCACHE_DIR -name '*.d' -delete
+    find $CCACHE_DIR -name '*.d' -exec rm '{}' +
 
     # Missing file -> consider the cached result broken.
     $CCACHE_COMPILE -c -MD test.c
index 8e7e8b0d5f5f18f175ac356bcf47e0c471a104d6..f4f969e3cfdeb74f023230adb55950e945cc9e0a 100644 (file)
@@ -25,7 +25,8 @@ SUITE_hardlink() {
     expect_stat 'files in cache' 1
     expect_equal_object_files reference_test1.o test1.o
 
-    local obj_in_cache=$(find $CCACHE_DIR -name '*.o')
+    local obj_in_cache
+    obj_in_cache=$(find $CCACHE_DIR -name '*.o')
     if [ ! $obj_in_cache -ef test1.o ]; then
         test_failed "Object file not hard-linked to cached object file"
     fi
index 0b42eef342eaafcbc8a9759a64a7cfc48e8f3628..fbbb78f27cdb84446d063bdc3f24993d94645071 100644 (file)
@@ -1,13 +1,16 @@
 SUITE_masquerading_PROBE() {
-    local compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
+    local compiler_binary
+    compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
     if [ "$(dirname $compiler_binary)" != . ]; then
         echo "compiler ($compiler_binary) not taken from PATH"
     fi
 }
 
 SUITE_masquerading_SETUP() {
-    local compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
-    local compiler_args=$(echo $COMPILER | cut -s -d' ' -f2-)
+    local compiler_binary
+    compiler_binary=$(echo $COMPILER | cut -d' ' -f1)
+    local compiler_args
+    compiler_args=$(echo $COMPILER | cut -s -d' ' -f2-)
 
     ln -s "$CCACHE" $compiler_binary
     CCACHE_COMPILE="./$compiler_binary $compiler_args"
index fdb8d0a2ffe349b9b8dce226d028275a70d1e486..12138d1597b6c51703082d28ebcba88821f81afd 100644 (file)
@@ -284,6 +284,61 @@ pch_suite_gcc() {
     expect_stat 'cache hit (direct)' 3
     expect_stat 'cache hit (preprocessed)' 0
     expect_stat 'cache miss' 3
+
+    # -------------------------------------------------------------------------
+    TEST "Use .gch, -fpch-preprocess, PCH_EXTSUM=1"
+
+    $REAL_COMPILER $SYSROOT -c pch.h
+    backdate pch.h.gch
+
+    echo "original checksum" > pch.h.gch.sum
+
+    CCACHE_PCH_EXTSUM=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+
+    CCACHE_PCH_EXTSUM=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+
+    echo "other checksum" > pch.h.gch.sum
+    CCACHE_PCH_EXTSUM=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 2
+
+    echo "original checksum" > pch.h.gch.sum
+    CCACHE_PCH_EXTSUM=1 CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 2
+
+    # -------------------------------------------------------------------------
+    TEST "Use .gch, -fpch-preprocess, no PCH_EXTSUM"
+
+    $REAL_COMPILER $SYSROOT -c pch.h
+    backdate pch.h.gch
+
+    echo "original checksum" > pch.h.gch.sum
+
+    CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+
+    CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+
+    # external checksum not used, so no cache miss when changed
+    echo "other checksum" > pch.h.gch.sum
+    CCACHE_SLOPPINESS="$DEFAULT_SLOPPINESS pch_defines time_macros" $CCACHE_COMPILE $SYSROOT -c -fpch-preprocess pch.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
 }
 
 pch_suite_clang() {
diff --git a/test/suites/sanitize_blacklist.bash b/test/suites/sanitize_blacklist.bash
new file mode 100644 (file)
index 0000000..a2411e9
--- /dev/null
@@ -0,0 +1,58 @@
+SUITE_sanitize_blacklist_PROBE() {
+    touch test.c blacklist.txt
+    if ! $REAL_COMPILER -c -fsanitize-blacklist=blacklist.txt \
+         test.c 2>/dev/null; then
+        echo "-fsanitize-blacklist not supported by compiler"
+    fi
+}
+
+SUITE_sanitize_blacklist_SETUP() {
+    generate_code 1 test1.c
+    echo "fun:foo" >blacklist.txt
+
+    unset CCACHE_NODIRECT
+}
+
+SUITE_sanitize_blacklist() {
+    # -------------------------------------------------------------------------
+    TEST "Compile OK"
+
+    $REAL_COMPILER -c -fsanitize-blacklist=blacklist.txt test1.c
+
+    $CCACHE_COMPILE -c -fsanitize-blacklist=blacklist.txt test1.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+    expect_stat 'files in cache' 2
+
+    $CCACHE_COMPILE -c -fsanitize-blacklist=blacklist.txt test1.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 1
+    expect_stat 'files in cache' 2
+
+    echo "fun:bar" >blacklist.txt
+
+    $CCACHE_COMPILE -c -fsanitize-blacklist=blacklist.txt test1.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+    expect_stat 'files in cache' 4
+
+    $CCACHE_COMPILE -c -fsanitize-blacklist=blacklist.txt test1.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache miss' 2
+    expect_stat 'files in cache' 4
+
+    # -------------------------------------------------------------------------
+    TEST "Compile failed"
+
+    if $REAL_COMPILER -c -fsanitize-blacklist=nosuchfile.txt test1.c 2>expected.stderr; then
+        test_failed "Expected an error compiling test1.c"
+    fi
+
+    rm blacklist.txt
+
+    if $CCACHE_COMPILE -c -fsanitize-blacklist=blacklist.txt test1.c 2>expected.stderr; then
+        test_failed "Expected an error compiling test1.c"
+    fi
+
+    expect_stat 'error hashing extra file' 1
+}
index 404367a9a74f9542cb4500700461e8404cafcdae..797822ffde0387c4e07928bb1b4acf3da14bba1f 100644 (file)
@@ -211,8 +211,8 @@ cct_check_int_eq(const char *file, int line, const char *expression,
 
 bool
 cct_check_str_eq(const char *file, int line, const char *expression,
-                 const char *expected, const char *actual, bool free1,
-                 bool free2)
+                 char *expected, char *actual,
+                 bool free1, bool free2)
 {
        bool result;
 
@@ -229,10 +229,10 @@ cct_check_str_eq(const char *file, int line, const char *expression,
        }
 
        if (free1) {
-               free((char *)expected);
+               free(expected);
        }
        if (free2) {
-               free((char *)actual);
+               free(actual);
        }
        return result;
 }
index 2f36c736ef1904071423fd7956016b4bdef609c7..317c2ca0f56f4757f1815e53f62df47d459fbc7c 100644 (file)
@@ -22,6 +22,7 @@
 // ============================================================================
 
 #define TEST_SUITE(name) \
+       unsigned suite_##name(unsigned _start_point); \
        unsigned suite_##name(unsigned _start_point) \
        { \
                unsigned _test_counter = 0; \
@@ -139,8 +140,8 @@ bool cct_check_float_eq(const char *file, int line, const char *expression,
 bool cct_check_int_eq(const char *file, int line, const char *expression,
                       int64_t expected, int64_t actual);
 bool cct_check_str_eq(const char *file, int line, const char *expression,
-                      const char *expected, const char *actual, bool free1,
-                      bool free2);
+                      char *expected, char *actual,
+                     bool free1, bool free2);
 bool cct_check_args_eq(const char *file, int line, const char *expression,
                        struct args *expected, struct args *actual,
                        bool free1, bool free2);
index 7b59788a68003b23e1cfb71942894e242b8ad56c..e3299b00e77d373892e8bc0e26be9b39810dde70 100644 (file)
 #undef SUITE
 // *INDENT-ON* enable uncrustify
 
-const char USAGE_TEXT[] =
-  "Usage:\n"
-  "    test [options]\n"
-  "\n"
-  "Options:\n"
-  "    -h, --help      print this help text\n"
-  "    -v, --verbose   enable verbose logging of tests\n";
+static const char USAGE_TEXT[] =
+       "Usage:\n"
+       "    test [options]\n"
+       "\n"
+       "Options:\n"
+       "    -h, --help      print this help text\n"
+       "    -v, --verbose   enable verbose logging of tests\n";
 
 int
 main(int argc, char **argv)
index 9815f14f5ee68810100cd1ece75ad9a81aaf8109..65c66d8d95f708643796a264a89774f3596e6c3a 100644 (file)
@@ -60,8 +60,8 @@ TEST(args_init_from_gcc_atfile)
 {
        struct args *args;
        const char *argtext =
-         "first\rsec\\\tond\tthi\\\\rd\nfourth  \tfif\\ th \"si'x\\\" th\""
-         " 'seve\nth'\\";
+               "first\rsec\\\tond\tthi\\\\rd\nfourth  \tfif\\ th \"si'x\\\" th\""
+               " 'seve\nth'\\";
 
        create_file("gcc_atfile", argtext);
 
@@ -198,13 +198,13 @@ TEST(args_insert)
        CHECK_INT_EQ(9, args->argc);
        args_insert(args, 1, src5, false);
        CHECK_STR_EQ_FREE2(
-         "first one alpha beta gamma second beta gamma fourth fifth",
-         args_to_string(args));
+               "first one alpha beta gamma second beta gamma fourth fifth",
+               args_to_string(args));
        CHECK_INT_EQ(10, args->argc);
        args_insert(args, 1, src6, false);
        CHECK_STR_EQ_FREE2(
-         "first one alpha beta gamma second beta gamma fourth fifth",
-         args_to_string(args));
+               "first one alpha beta gamma second beta gamma fourth fifth",
+               args_to_string(args));
        CHECK_INT_EQ(10, args->argc);
 
        args_free(args);
index bb49913b9cf4b4ab72582a8043e2e44af91493fa..fb30c98498b262c511789fed7efd6e32630255f2 100644 (file)
@@ -159,9 +159,9 @@ TEST(cpp_only_flags_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
 TEST(dependency_flags_that_take_an_argument_should_not_require_space_delimiter)
 {
        struct args *orig = args_init_from_string(
-         "cc -c -MMD -MFfoo.d -MT mt -MTmt -MQmq foo.c -o foo.o");
+               "cc -c -MMD -MFfoo.d -MT mt -MTmt -MQmq foo.c -o foo.o");
        struct args *exp_cpp = args_init_from_string(
-         "cc -MMD -MFfoo.d -MT mt -MTmt -MQmq");
+               "cc -MMD -MFfoo.d -MT mt -MTmt -MQmq");
        struct args *exp_cc = args_init_from_string("cc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -223,9 +223,9 @@ TEST(sysroot_with_separate_argument_should_be_rewritten_if_basedir_is_used)
 TEST(MF_flag_with_immediate_argument_should_work_as_last_argument)
 {
        struct args *orig = args_init_from_string(
-         "cc -c foo.c -o foo.o -MMD -MT bar -MFfoo.d");
+               "cc -c foo.c -o foo.o -MMD -MT bar -MFfoo.d");
        struct args *exp_cpp = args_init_from_string(
-         "cc -MMD -MT bar -MFfoo.d");
+               "cc -MMD -MT bar -MFfoo.d");
        struct args *exp_cc = args_init_from_string("cc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -240,9 +240,9 @@ TEST(MF_flag_with_immediate_argument_should_work_as_last_argument)
 TEST(MT_flag_with_immediate_argument_should_work_as_last_argument)
 {
        struct args *orig = args_init_from_string(
-         "cc -c foo.c -o foo.o -MMD -MFfoo.d -MT foo -MTbar");
+               "cc -c foo.c -o foo.o -MMD -MFfoo.d -MT foo -MTbar");
        struct args *exp_cpp = args_init_from_string(
-         "cc -MMD -MFfoo.d -MT foo -MTbar");
+               "cc -MMD -MFfoo.d -MT foo -MTbar");
        struct args *exp_cc = args_init_from_string("cc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -257,9 +257,9 @@ TEST(MT_flag_with_immediate_argument_should_work_as_last_argument)
 TEST(MQ_flag_with_immediate_argument_should_work_as_last_argument)
 {
        struct args *orig = args_init_from_string(
-         "cc -c foo.c -o foo.o -MMD -MFfoo.d -MQ foo -MQbar");
+               "cc -c foo.c -o foo.o -MMD -MFfoo.d -MQ foo -MQbar");
        struct args *exp_cpp = args_init_from_string(
-         "cc -MMD -MFfoo.d -MQ foo -MQbar");
+               "cc -MMD -MFfoo.d -MQ foo -MQbar");
        struct args *exp_cc = args_init_from_string("cc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -274,9 +274,9 @@ TEST(MQ_flag_with_immediate_argument_should_work_as_last_argument)
 TEST(MQ_flag_without_immediate_argument_should_not_add_MQobj)
 {
        struct args *orig = args_init_from_string(
-         "gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
+               "gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
        struct args *exp_cpp = args_init_from_string(
-         "gcc -MD -MP -MFfoo.d -MQ foo.d");
+               "gcc -MD -MP -MFfoo.d -MQ foo.d");
        struct args *exp_cc = args_init_from_string("gcc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -291,9 +291,9 @@ TEST(MQ_flag_without_immediate_argument_should_not_add_MQobj)
 TEST(MT_flag_without_immediate_argument_should_not_add_MTobj)
 {
        struct args *orig = args_init_from_string(
-         "gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
+               "gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
        struct args *exp_cpp = args_init_from_string(
-         "gcc -MD -MP -MFfoo.d -MT foo.d");
+               "gcc -MD -MP -MFfoo.d -MT foo.d");
        struct args *exp_cc = args_init_from_string("gcc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -308,9 +308,9 @@ TEST(MT_flag_without_immediate_argument_should_not_add_MTobj)
 TEST(MQ_flag_with_immediate_argument_should_not_add_MQobj)
 {
        struct args *orig = args_init_from_string(
-         "gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
+               "gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
        struct args *exp_cpp = args_init_from_string(
-         "gcc -MD -MP -MFfoo.d -MQfoo.d");
+               "gcc -MD -MP -MFfoo.d -MQfoo.d");
        struct args *exp_cc = args_init_from_string("gcc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -325,9 +325,9 @@ TEST(MQ_flag_with_immediate_argument_should_not_add_MQobj)
 TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
 {
        struct args *orig = args_init_from_string(
-         "gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
+               "gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
        struct args *exp_cpp = args_init_from_string(
-         "gcc -MD -MP -MFfoo.d -MTfoo.d");
+               "gcc -MD -MP -MFfoo.d -MTfoo.d");
        struct args *exp_cc = args_init_from_string("gcc -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
        create_file("foo.c", "");
@@ -342,7 +342,7 @@ TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
 TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path)
 {
        struct args *orig = args_init_from_string(
-         "gcc -c -fprofile-generate=some/dir foo.c");
+               "gcc -c -fprofile-generate=some/dir foo.c");
        struct args *exp_cpp = args_init_from_string("gcc");
        struct args *exp_cc = args_init_from_string("gcc");
        struct args *act_cpp = NULL, *act_cc = NULL;
@@ -369,11 +369,11 @@ TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path)
 TEST(fprofile_flag_with_nonexisting_dir_should_not_be_rewritten)
 {
        struct args *orig = args_init_from_string(
-         "gcc -c -fprofile-generate=some/dir foo.c");
+               "gcc -c -fprofile-generate=some/dir foo.c");
        struct args *exp_cpp = args_init_from_string(
-         "gcc -fprofile-generate=some/dir");
+               "gcc -fprofile-generate=some/dir");
        struct args *exp_cc = args_init_from_string(
-         "gcc -fprofile-generate=some/dir -c");
+               "gcc -fprofile-generate=some/dir -c");
        struct args *act_cpp = NULL, *act_cc = NULL;
 
        create_file("foo.c", "");
index fb50f357b68c9ea9f03062e85c621351bb7eed2c..263e649706f6f21764f604fc603799a80b384b3f 100644 (file)
@@ -24,7 +24,7 @@ TEST_SUITE(compopt)
 
 TEST(option_table_should_be_sorted)
 {
-       bool compopt_verify_sortedness();
+       bool compopt_verify_sortedness(void);
        CHECK(compopt_verify_sortedness());
 }
 
index 0718a2e8cac7cb12a10f56b32dbc1886c4f59ac8..e61aa6ac44135bc6490581d16cfd5252b6f51620 100644 (file)
 #include "framework.h"
 #include "util.h"
 
-#define N_CONFIG_ITEMS 31
+#define N_CONFIG_ITEMS 33
 static struct {
        char *descr;
-       const char *origin;
+       char *origin;
 } received_conf_items[N_CONFIG_ITEMS];
 static size_t n_received_conf_items = 0;
 
@@ -30,7 +30,7 @@ conf_item_receiver(const char *descr, const char *origin, void *context)
 {
        (void)context;
        received_conf_items[n_received_conf_items].descr = x_strdup(descr);
-       received_conf_items[n_received_conf_items].origin = origin;
+       received_conf_items[n_received_conf_items].origin = x_strdup(origin);
        ++n_received_conf_items;
 }
 
@@ -40,6 +40,7 @@ free_received_conf_items(void)
        while (n_received_conf_items > 0) {
                --n_received_conf_items;
                free(received_conf_items[n_received_conf_items].descr);
+               free(received_conf_items[n_received_conf_items].origin);
        }
 }
 
@@ -57,6 +58,7 @@ TEST(conf_create)
        CHECK(!conf->compression);
        CHECK_INT_EQ(6, conf->compression_level);
        CHECK_STR_EQ("", conf->cpp_extension);
+       CHECK(!conf->debug);
        CHECK(conf->direct_mode);
        CHECK(!conf->disable);
        CHECK_STR_EQ("", conf->extra_files_to_hash);
@@ -69,6 +71,7 @@ TEST(conf_create)
        CHECK_INT_EQ(0, conf->max_files);
        CHECK_INT_EQ((uint64_t)5 * 1000 * 1000 * 1000, conf->max_size);
        CHECK_STR_EQ("", conf->path);
+       CHECK(!conf->pch_external_checksum);
        CHECK_STR_EQ("", conf->prefix_command);
        CHECK_STR_EQ("", conf->prefix_command_cpp);
        CHECK(!conf->read_only);
@@ -91,46 +94,47 @@ TEST(conf_read_valid_config)
        user = getenv("USER");
        CHECK_STR_EQ("rabbit", user);
        create_file(
-         "ccache.conf",
+               "ccache.conf",
 #ifndef _WIN32
-         "base_dir =  /$USER/foo/${USER} \n"
+               "base_dir =  /$USER/foo/${USER} \n"
 #else
-         "base_dir = C:/$USER/foo/${USER}\n"
+               "base_dir = C:/$USER/foo/${USER}\n"
 #endif
-         "cache_dir=\n"
-         "cache_dir = $USER$/${USER}/.ccache\n"
-         "\n"
-         "\n"
-         "  #A comment\n"
-         " cache_dir_levels = 4\n"
-         "\t compiler = foo\n"
-         "compiler_check = none\n"
-         "compression=true\n"
-         "compression_level= 2\n"
-         "cpp_extension = .foo\n"
-         "direct_mode = false\n"
-         "disable = true\n"
-         "extra_files_to_hash = a:b c:$USER\n"
-         "hard_link = true\n"
-         "hash_dir = false\n"
-         "ignore_headers_in_manifest = a:b/c\n"
-         "keep_comments_cpp = true\n"
-         "limit_multiple = 1.0\n"
-         "log_file = $USER${USER} \n"
-         "max_files = 17\n"
-         "max_size = 123M\n"
-         "path = $USER.x\n"
-         "prefix_command = x$USER\n"
-         "prefix_command_cpp = y\n"
-         "read_only = true\n"
-         "read_only_direct = true\n"
-         "recache = true\n"
-         "run_second_cpp = false\n"
-         "sloppiness =     file_macro   ,time_macros,  include_file_mtime,include_file_ctime,file_stat_matches,pch_defines ,  no_system_headers  \n"
-         "stats = false\n"
-         "temporary_dir = ${USER}_foo\n"
-         "umask = 777\n"
-         "unify = true"); // Note: no newline.
+               "cache_dir=\n"
+               "cache_dir = $USER$/${USER}/.ccache\n"
+               "\n"
+               "\n"
+               "  #A comment\n"
+               " cache_dir_levels = 4\n"
+               "\t compiler = foo\n"
+               "compiler_check = none\n"
+               "compression=true\n"
+               "compression_level= 2\n"
+               "cpp_extension = .foo\n"
+               "direct_mode = false\n"
+               "disable = true\n"
+               "extra_files_to_hash = a:b c:$USER\n"
+               "hard_link = true\n"
+               "hash_dir = false\n"
+               "ignore_headers_in_manifest = a:b/c\n"
+               "keep_comments_cpp = true\n"
+               "limit_multiple = 1.0\n"
+               "log_file = $USER${USER} \n"
+               "max_files = 17\n"
+               "max_size = 123M\n"
+               "path = $USER.x\n"
+               "pch_external_checksum = true\n"
+               "prefix_command = x$USER\n"
+               "prefix_command_cpp = y\n"
+               "read_only = true\n"
+               "read_only_direct = true\n"
+               "recache = true\n"
+               "run_second_cpp = false\n"
+               "sloppiness =     file_macro   ,time_macros,  include_file_mtime,include_file_ctime,file_stat_matches,file_stat_matches_ctime,pch_defines ,  no_system_headers  \n"
+               "stats = false\n"
+               "temporary_dir = ${USER}_foo\n"
+               "umask = 777\n"
+               "unify = true"); // Note: no newline.
        CHECK(conf_read(conf, "ccache.conf", &errmsg));
        CHECK(!errmsg);
 
@@ -158,6 +162,7 @@ TEST(conf_read_valid_config)
        CHECK_INT_EQ(17, conf->max_files);
        CHECK_INT_EQ(123 * 1000 * 1000, conf->max_size);
        CHECK_STR_EQ_FREE1(format("%s.x", user), conf->path);
+       CHECK(conf->pch_external_checksum);
        CHECK_STR_EQ_FREE1(format("x%s", user), conf->prefix_command);
        CHECK_STR_EQ("y", conf->prefix_command_cpp);
        CHECK(conf->read_only);
@@ -166,8 +171,8 @@ TEST(conf_read_valid_config)
        CHECK(!conf->run_second_cpp);
        CHECK_INT_EQ(SLOPPY_INCLUDE_FILE_MTIME|SLOPPY_INCLUDE_FILE_CTIME|
                     SLOPPY_FILE_MACRO|SLOPPY_TIME_MACROS|
-                    SLOPPY_FILE_STAT_MATCHES|SLOPPY_NO_SYSTEM_HEADERS|
-                    SLOPPY_PCH_DEFINES,
+                    SLOPPY_FILE_STAT_MATCHES|SLOPPY_FILE_STAT_MATCHES_CTIME|
+                    SLOPPY_NO_SYSTEM_HEADERS|SLOPPY_PCH_DEFINES,
                     conf->sloppiness);
        CHECK(!conf->stats);
        CHECK_STR_EQ_FREE1(format("%s_foo", user), conf->temporary_dir);
@@ -324,13 +329,13 @@ TEST(verify_dir_levels)
        create_file("ccache.conf", "cache_dir_levels = 0");
        CHECK(!conf_read(conf, "ccache.conf", &errmsg));
        CHECK_STR_EQ_FREE2(
-         "ccache.conf:1: cache directory levels must be between 1 and 8",
-         errmsg);
+               "ccache.conf:1: cache directory levels must be between 1 and 8",
+               errmsg);
        create_file("ccache.conf", "cache_dir_levels = 9");
        CHECK(!conf_read(conf, "ccache.conf", &errmsg));
        CHECK_STR_EQ_FREE2(
-         "ccache.conf:1: cache directory levels must be between 1 and 8",
-         errmsg);
+               "ccache.conf:1: cache directory levels must be between 1 and 8",
+               errmsg);
 
        conf_free(conf);
 }
@@ -378,6 +383,50 @@ TEST(conf_set_existing_value)
        CHECK_STR_EQ_FREE2("path = vanilla\nstats = chocolate\n", data);
 }
 
+TEST(conf_print_existing_value)
+{
+       struct conf *conf = conf_create();
+       conf->max_files = 42;
+       char *errmsg;
+       {
+               FILE *log = fopen("log", "w");
+               CHECK(log);
+               CHECK(conf_print_value(conf, "max_files", log, &errmsg));
+               fclose(log);
+       }
+       {
+               FILE *log = fopen("log", "r");
+               CHECK(log);
+               char buf[100];
+               CHECK(fgets(buf, 100, log));
+               CHECK_STR_EQ("42\n", buf);
+               fclose(log);
+       }
+       conf_free(conf);
+}
+
+TEST(conf_print_unknown_value)
+{
+       struct conf *conf = conf_create();
+       char *errmsg;
+       {
+               FILE *log = fopen("log", "w");
+               CHECK(log);
+               CHECK(!conf_print_value(conf, "foo", log, &errmsg));
+               CHECK_STR_EQ_FREE2("unknown configuration option \"foo\"",
+                                  errmsg);
+               fclose(log);
+       }
+       {
+               FILE *log = fopen("log", "r");
+               CHECK(log);
+               char buf[100];
+               CHECK(!fgets(buf, 100, log));
+               fclose(log);
+       }
+       conf_free(conf);
+}
+
 TEST(conf_print_items)
 {
        size_t i;
@@ -391,6 +440,7 @@ TEST(conf_print_items)
                8,
                "ce",
                false,
+               false,
                true,
                "efth",
                true,
@@ -402,6 +452,7 @@ TEST(conf_print_items)
                4711,
                98.7 * 1000 * 1000,
                "p",
+               true,
                "pc",
                "pcc",
                true,
@@ -410,8 +461,8 @@ TEST(conf_print_items)
                .run_second_cpp = false,
                SLOPPY_FILE_MACRO|SLOPPY_INCLUDE_FILE_MTIME|
                SLOPPY_INCLUDE_FILE_CTIME|SLOPPY_TIME_MACROS|
-               SLOPPY_FILE_STAT_MATCHES|SLOPPY_PCH_DEFINES|
-               SLOPPY_NO_SYSTEM_HEADERS,
+               SLOPPY_FILE_STAT_MATCHES|SLOPPY_FILE_STAT_MATCHES_CTIME|
+               SLOPPY_PCH_DEFINES|SLOPPY_NO_SYSTEM_HEADERS,
                false,
                "td",
                022,
@@ -439,6 +490,7 @@ TEST(conf_print_items)
        CHECK_STR_EQ("compression = true", received_conf_items[n++].descr);
        CHECK_STR_EQ("compression_level = 8", received_conf_items[n++].descr);
        CHECK_STR_EQ("cpp_extension = ce", received_conf_items[n++].descr);
+       CHECK_STR_EQ("debug = false", received_conf_items[n++].descr);
        CHECK_STR_EQ("direct_mode = false", received_conf_items[n++].descr);
        CHECK_STR_EQ("disable = true", received_conf_items[n++].descr);
        CHECK_STR_EQ("extra_files_to_hash = efth", received_conf_items[n++].descr);
@@ -452,6 +504,7 @@ TEST(conf_print_items)
        CHECK_STR_EQ("max_files = 4711", received_conf_items[n++].descr);
        CHECK_STR_EQ("max_size = 98.7M", received_conf_items[n++].descr);
        CHECK_STR_EQ("path = p", received_conf_items[n++].descr);
+       CHECK_STR_EQ("pch_external_checksum = true", received_conf_items[n++].descr);
        CHECK_STR_EQ("prefix_command = pc", received_conf_items[n++].descr);
        CHECK_STR_EQ("prefix_command_cpp = pcc", received_conf_items[n++].descr);
        CHECK_STR_EQ("read_only = true", received_conf_items[n++].descr);
@@ -460,7 +513,7 @@ TEST(conf_print_items)
        CHECK_STR_EQ("run_second_cpp = false", received_conf_items[n++].descr);
        CHECK_STR_EQ("sloppiness = file_macro, include_file_mtime,"
                     " include_file_ctime, time_macros, pch_defines,"
-                    " file_stat_matches, no_system_headers",
+                    " file_stat_matches, file_stat_matches_ctime, no_system_headers",
                     received_conf_items[n++].descr);
        CHECK_STR_EQ("stats = false", received_conf_items[n++].descr);
        CHECK_STR_EQ("temporary_dir = td", received_conf_items[n++].descr);
index 674bca6fa338495a7b6df44f02cfb136e5436583..5278560e2e32377a28c5b8f422d31e8d0f29595c 100644 (file)
 // This file contains tests for functions in hash.c.
 
 #include "../src/ccache.h"
+#include "../src/hash.h"
 #include "framework.h"
 
-TEST_SUITE(hash)
+TEST_SUITE(mdfour)
 
 TEST(test_vectors_from_rfc_1320_should_be_correct)
 {
-       struct mdfour h;
+       {
+               struct hash *h = hash_init();
+               hash_string(h, "");
+               CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(h));
+               hash_free(h);
+       }
 
-       hash_start(&h);
-       hash_string(&h, "");
-       CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(&h));
+       {
+               struct hash *h = hash_init();
+               hash_string(h, "a");
+               CHECK_STR_EQ_FREE2("bde52cb31de33e46245e05fbdbd6fb24-1", hash_result(h));
+               hash_free(h);
+       }
 
-       hash_start(&h);
-       hash_string(&h, "a");
-       CHECK_STR_EQ_FREE2("bde52cb31de33e46245e05fbdbd6fb24-1", hash_result(&h));
+       {
+               struct hash *h = hash_init();
+               hash_string(h, "message digest");
+               CHECK_STR_EQ_FREE2("d9130a8164549fe818874806e1c7014b-14", hash_result(h));
+               hash_free(h);
+       }
 
-       hash_start(&h);
-       hash_string(&h, "message digest");
-       CHECK_STR_EQ_FREE2("d9130a8164549fe818874806e1c7014b-14", hash_result(&h));
-
-       hash_start(&h);
-       hash_string(
-         &h,
-         "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
-       CHECK_STR_EQ_FREE2("e33b4ddc9c38f2199c3e7b164fcc0536-80", hash_result(&h));
+       {
+               struct hash *h = hash_init();
+               hash_string(
+                       h,
+                       "12345678901234567890123456789012345678901234567890123456789012345678901"
+                       "234567890");
+               CHECK_STR_EQ_FREE2("e33b4ddc9c38f2199c3e7b164fcc0536-80", hash_result(h));
+               hash_free(h);
+       }
 }
 
 TEST(hash_result_should_be_idempotent)
 {
-       struct mdfour h;
+       struct hash *h = hash_init();
+
+       hash_string(h, "");
+       CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(h));
+       CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(h));
 
-       hash_start(&h);
-       hash_string(&h, "");
-       CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(&h));
-       CHECK_STR_EQ_FREE2("31d6cfe0d16ae931b73c59d7e0c089c0-0", hash_result(&h));
+       hash_free(h);
 }
 
 TEST_SUITE_END
index dcbaa842aeff4e84b108a90428854649eab3ef01..2b2dbc9b1e488bb6b1c8153a37f1e393de93c45c 100644 (file)
@@ -25,123 +25,144 @@ TEST_SUITE(hashutil)
 
 TEST(hash_command_output_simple)
 {
-       struct mdfour h1, h2;
-       hash_start(&h1);
-       hash_start(&h2);
-       CHECK(hash_command_output(&h1, "echo", "not used"));
-       CHECK(hash_command_output(&h2, "echo", "not used"));
-       CHECK(hash_equal(&h1, &h2));
+       struct hash *h1 = hash_init();
+       struct hash *h2 = hash_init();
+
+       CHECK(hash_command_output(h1, "echo", "not used"));
+       CHECK(hash_command_output(h2, "echo", "not used"));
+       CHECK(hash_equal(h1, h2));
+
+       hash_free(h2);
+       hash_free(h1);
 }
 
 TEST(hash_command_output_space_removal)
 {
-       struct mdfour h1, h2;
-       hash_start(&h1);
-       hash_start(&h2);
-       CHECK(hash_command_output(&h1, "echo", "not used"));
-       CHECK(hash_command_output(&h2, " echo ", "not used"));
-       CHECK(hash_equal(&h1, &h2));
+       struct hash *h1 = hash_init();
+       struct hash *h2 = hash_init();
+
+       CHECK(hash_command_output(h1, "echo", "not used"));
+       CHECK(hash_command_output(h2, " echo ", "not used"));
+       CHECK(hash_equal(h1, h2));
+
+       hash_free(h2);
+       hash_free(h1);
 }
 
 TEST(hash_command_output_hash_inequality)
 {
-       struct mdfour h1, h2;
-       hash_start(&h1);
-       hash_start(&h2);
-       CHECK(hash_command_output(&h1, "echo foo", "not used"));
-       CHECK(hash_command_output(&h2, "echo bar", "not used"));
-       CHECK(!hash_equal(&h1, &h2));
+       struct hash *h1 = hash_init();
+       struct hash *h2 = hash_init();
+
+       CHECK(hash_command_output(h1, "echo foo", "not used"));
+       CHECK(hash_command_output(h2, "echo bar", "not used"));
+       CHECK(!hash_equal(h1, h2));
+
+       hash_free(h2);
+       hash_free(h1);
 }
 
 TEST(hash_command_output_compiler_substitution)
 {
-       struct mdfour h1, h2;
-       hash_start(&h1);
-       hash_start(&h2);
-       CHECK(hash_command_output(&h1, "echo foo", "not used"));
-       CHECK(hash_command_output(&h2, "%compiler% foo", "echo"));
-       CHECK(hash_equal(&h1, &h2));
+       struct hash *h1 = hash_init();
+       struct hash *h2 = hash_init();
+
+       CHECK(hash_command_output(h1, "echo foo", "not used"));
+       CHECK(hash_command_output(h2, "%compiler% foo", "echo"));
+       CHECK(hash_equal(h1, h2));
+
+       hash_free(h2);
+       hash_free(h1);
 }
 
 TEST(hash_command_output_stdout_versus_stderr)
 {
-       struct mdfour h1, h2;
-       hash_start(&h1);
-       hash_start(&h2);
+       struct hash *h1 = hash_init();
+       struct hash *h2 = hash_init();
+
 #ifndef _WIN32
        create_file("stderr.sh", "#!/bin/sh\necho foo >&2\n");
        chmod("stderr.sh", 0555);
-       CHECK(hash_command_output(&h1, "echo foo", "not used"));
-       CHECK(hash_command_output(&h2, "./stderr.sh", "not used"));
+       CHECK(hash_command_output(h1, "echo foo", "not used"));
+       CHECK(hash_command_output(h2, "./stderr.sh", "not used"));
 #else
        create_file("stderr.bat", "@echo off\r\necho foo>&2\r\n");
-       CHECK(hash_command_output(&h1, "echo foo", "not used"));
-       CHECK(hash_command_output(&h2, "stderr.bat", "not used"));
+       CHECK(hash_command_output(h1, "echo foo", "not used"));
+       CHECK(hash_command_output(h2, "stderr.bat", "not used"));
 #endif
-       CHECK(hash_equal(&h1, &h2));
+       CHECK(hash_equal(h1, h2));
+
+       hash_free(h2);
+       hash_free(h1);
 }
 
 TEST(hash_multicommand_output)
 {
-       struct mdfour h1, h2;
-       hash_start(&h1);
-       hash_start(&h2);
+       struct hash *h1 = hash_init();
+       struct hash *h2 = hash_init();
+
 #ifndef _WIN32
        create_file("foo.sh", "#!/bin/sh\necho foo\necho bar\n");
        chmod("foo.sh", 0555);
-       CHECK(hash_multicommand_output(&h2, "echo foo; echo bar", "not used"));
-       CHECK(hash_multicommand_output(&h1, "./foo.sh", "not used"));
+       CHECK(hash_multicommand_output(h2, "echo foo; echo bar", "not used"));
+       CHECK(hash_multicommand_output(h1, "./foo.sh", "not used"));
 #else
        create_file("foo.bat", "@echo off\r\necho foo\r\necho bar\r\n");
-       CHECK(hash_multicommand_output(&h2, "echo foo; echo bar", "not used"));
-       CHECK(hash_multicommand_output(&h1, "foo.bat", "not used"));
+       CHECK(hash_multicommand_output(h2, "echo foo; echo bar", "not used"));
+       CHECK(hash_multicommand_output(h1, "foo.bat", "not used"));
 #endif
-       CHECK(hash_equal(&h1, &h2));
+       CHECK(hash_equal(h1, h2));
+
+       hash_free(h2);
+       hash_free(h1);
 }
 
 TEST(hash_multicommand_output_error_handling)
 {
-       struct mdfour h1, h2;
-       hash_start(&h1);
-       hash_start(&h2);
-       CHECK(!hash_multicommand_output(&h2, "false; true", "not used"));
+       struct hash *h1 = hash_init();
+       struct hash *h2 = hash_init();
+
+       CHECK(!hash_multicommand_output(h2, "false; true", "not used"));
+
+       hash_free(h2);
+       hash_free(h1);
 }
 
 TEST(check_for_temporal_macros)
 {
        const char time_start[] =
-         "__TIME__\n"
-         "int a;\n";
+               "__TIME__\n"
+               "int a;\n";
        const char time_middle[] =
-         "#define a __TIME__\n"
-         "int a;\n";
+               "#define a __TIME__\n"
+               "int a;\n";
        const char time_end[] =
-         "#define a __TIME__";
+               "#define a __TIME__";
 
        const char date_start[] =
-         "__DATE__\n"
-         "int ab;\n";
+               "__DATE__\n"
+               "int ab;\n";
        const char date_middle[] =
-         "#define ab __DATE__\n"
-         "int ab;\n";
+               "#define ab __DATE__\n"
+               "int ab;\n";
        const char date_end[] =
-         "#define ab __DATE__";
+               "#define ab __DATE__";
 
        const char no_temporal[] =
-         "#define ab _ _DATE__\n"
-         "#define ab __ DATE__\n"
-         "#define ab __D ATE__\n"
-         "#define ab __DA TE__\n"
-         "#define ab __DAT E__\n"
-         "#define ab __DATE __\n"
-         "#define ab __DATE_ _\n"
-         "#define ab _ _TIME__\n"
-         "#define ab __ TIME__\n"
-         "#define ab __T IME__\n"
-         "#define ab __TI ME__\n"
-         "#define ab __TIM E__\n"
-         "#define ab __TIME __\n"
-         "#define ab __TIME_ _\n";
+               "#define ab _ _DATE__\n"
+               "#define ab __ DATE__\n"
+               "#define ab __D ATE__\n"
+               "#define ab __DA TE__\n"
+               "#define ab __DAT E__\n"
+               "#define ab __DATE __\n"
+               "#define ab __DATE_ _\n"
+               "#define ab _ _TIME__\n"
+               "#define ab __ TIME__\n"
+               "#define ab __T IME__\n"
+               "#define ab __TI ME__\n"
+               "#define ab __TIM E__\n"
+               "#define ab __TIME __\n"
+               "#define ab __TIME_ _\n";
 
        CHECK(check_for_temporal_macros(time_start + 0, sizeof(time_start) - 0));
        CHECK(!check_for_temporal_macros(time_start + 1, sizeof(time_start) - 1));
index 38b44191157298b9e630641b30d693818b33bbcc..8646a3d643f4d700c25f22728088f439284a38c5 100644 (file)
@@ -166,8 +166,8 @@ TEST(format_parsable_size_with_suffix)
        CHECK_STR_EQ_FREE2("1.0G",
                           format_parsable_size_with_suffix(1000 * 1000 * 1000));
        CHECK_STR_EQ_FREE2(
-         "17.1G",
-         format_parsable_size_with_suffix(17.11 * 1000 * 1000 * 1000));
+               "17.1G",
+               format_parsable_size_with_suffix(17.11 * 1000 * 1000 * 1000));
 }
 
 TEST(parse_size_with_suffix)
@@ -199,4 +199,12 @@ TEST(parse_size_with_suffix)
        }
 }
 
+TEST(format_command)
+{
+       char *argv[] = {"foo", "bar", NULL};
+
+       CHECK_STR_EQ_FREE2("foo bar\n", format_command(argv));
+
+}
+
 TEST_SUITE_END