-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)
+<?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
<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>
<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
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 \
generated_sources = \
src/version.c
3pp_sources = \
- src/getopt_long.c \
+ @getopt_long_c@ \
src/hashtable.c \
src/hashtable_itr.c \
src/murmurhashneutral2.c \
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:
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)
.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
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@
==============================
[](https://travis-ci.org/ccache/ccache)
+[](https://lgtm.com/projects/g/ccache/ccache/context:cpp)
+[](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
LDFLAGS
CFLAGS
CC
+disable_man
test_suites
include_dev_mk
+getopt_long_c
+no_implicit_fallthrough_warning
extra_libs
host_os
host_vendor
ac_subst_files=''
ac_user_opts='
enable_option_checking
+enable_more_warnings
with_bundled_zlib
+enable_man
'
ac_precious_vars='build_alias
host_alias
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)
+
+
+
# The later defininition of _XOPEN_SOURCE disables certain features
# on Linux, so we need _GNU_SOURCE to re-enable them (makedev, tm_zone).
;;
*)
-$as_echo "#define _XOPEN_SOURCE 600" >>confdefs.h
+$as_echo "#define _XOPEN_SOURCE 700" >>confdefs.h
;;
esac
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'
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 :
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
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 :
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
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
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;}
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"
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
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)
# 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
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>],
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
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"
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`
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)
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
src/conf.h \
src/counters.h \
src/getopt_long.h \
+ src/hash.h \
src/hashtable.h \
src/hashtable_itr.h \
src/hashtable_private.h \
src/mdfour.h \
src/murmurhashneutral2.h \
src/system.h \
+ src/unify.h \
unittest/framework.h \
unittest/util.h
generated_headers = \
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)
%.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:
.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)
* 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>
* 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>
* 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>
* 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!
+<?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
<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>
</li>\r
<li>\r
<p>\r
+Gabriel Scherer <<a href="mailto:gabriel.scherer@gmail.com">gabriel.scherer@gmail.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Geert Bosch <<a href="mailto:geert@mongodb.com">geert@mongodb.com</a>>\r
</p>\r
</li>\r
<li>\r
<p>\r
+Geert Kloosterman <<a href="mailto:geert.kloosterman@brightcomputing.com">geert.kloosterman@brightcomputing.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Grigory Entin <<a href="mailto:grigorye@dins.ru">grigorye@dins.ru</a>>\r
</p>\r
</li>\r
<li>\r
<p>\r
+Havard Graff <<a href="mailto:havard.graff@gmail.com">havard.graff@gmail.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Hongli Lai <<a href="mailto:hongli@phusion.nl">hongli@phusion.nl</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Mike Gulick <<a href="mailto:mgulick@mathworks.com">mgulick@mathworks.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Mikhail Kolomeytsev <<a href="mailto:mkolom@yandex-team.ru">mkolom@yandex-team.ru</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Rafael Kitover <<a href="mailto:rkitover@gmail.com">rkitover@gmail.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Ramiro Polla <<a href="mailto:ramiro.polla@gmail.com">ramiro.polla@gmail.com</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Thomas Otto <<a href="mailto:thomas.otto@psd-fs.de">thomas.otto@psd-fs.de</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Thomas Röfer <<a href="mailto:Thomas.Roefer@dfki.de">Thomas.Roefer@dfki.de</a>>\r
</p>\r
</li>\r
</li>\r
<li>\r
<p>\r
+Xavier RENE-CORAIL <<a href="mailto:xavier.renecorail@gmail.com">xavier.renecorail@gmail.com</a>>\r
+</p>\r
+</li>\r
+<li>\r
+<p>\r
Yiding Jia <<a href="mailto:yiding@fb.com">yiding@fb.com</a>>\r
</p>\r
</li>\r
<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
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
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
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
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.
| 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.
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-** 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
----------------------------------
+<?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
<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>
</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
</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
</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 “.sum” added\r
+ (e.g. “pre.h.gch.sum”), 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
</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
<td align="left" valign="top"><p class="table">Preprocessing the source code using the compiler’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
</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’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><objectfile>.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><objectfile>.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><objectfile>.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><objectfile>.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><objectfile>.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><objectfile>.ccache-*</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><objectfile>.ccache-input-text</strong> for the two builds. This together\r
+ with the <strong><objectfile>.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
<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
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
- 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.
+<?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
<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>
</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 “Cache debugging”\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 “stats updated” 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 “stats zero time” to “stats zeroed” 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’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’t be detected (e.g. if it is named <strong>cc</strong>), use safer\r
+ defaults that won’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
</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
</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
<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
.\" 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
.\" -----------------------------------------------------------------
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
\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
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
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\&.
lt lt
lt lt
lt lt
+lt lt
+lt lt
lt lt.
T{
.sp
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
.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:
--- /dev/null
+# _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
+
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
;;
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
// 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
}
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--) {
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],
#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;
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;
args_free(prefix);
}
+
+static void failed(void) ATTR_NORETURN;
+
// Something went badly wrong - just execute the real compiler.
static void
failed(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)
{
}
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;
}
// 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
DWORD attributes = GetFileAttributes(path);
if (attributes != INVALID_FILE_ATTRIBUTES &&
attributes & FILE_ATTRIBUTE_DIRECTORY) {
- goto ignore;
+ goto out;
}
#endif
}
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.
&& (ignore[ignore_len-1] == DIR_DELIM_CH
|| canonical[ignore_len] == DIR_DELIM_CH
|| canonical[ignore_len] == '\0')) {
- goto ignore;
+ goto out;
}
}
}
// 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) {
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) {
}
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) {
conf->direct_mode = false;
}
// Fall through.
-ignore:
+out:
+ hash_free(fhash);
free(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;
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;
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++;
}
} 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] = ' ';
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++;
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:
// 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);
}
}
- 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;
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;
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.
}
// Create or update the manifest file.
-void update_manifest_file(void)
+static void
+update_manifest_file(void)
{
if (!conf->direct_mode
|| !included_files
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;
}
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();
// 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);
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;
}
// 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")) {
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);
}
}
// 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>:
// 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);
// 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) {
}
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);
}
}
+ // 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;
// 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;
// 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++) {
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) {
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]);
//
// 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");
// (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")) {
}
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;
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);
}
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)) {
}
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;
}
if (should_create_initial_config) {
- create_initial_config_file(conf, primary_config_path);
+ create_initial_config_file(primary_config_path);
}
exitfn_init();
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;
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[])
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);
}
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);
}
// 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");
}
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'},
};
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);
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();
case 's': // --show-stats
initialize();
- stats_summary(conf);
+ stats_summary();
break;
case 'V': // --version
case 'z': // --zero-stats
initialize();
stats_zero();
- printf("Statistics cleared\n");
+ printf("Statistics zeroed\n");
break;
default:
return 0;
}
+int ccache_main(int argc, char *argv[]);
+
int
ccache_main(int argc, char *argv[])
{
free(program_name);
ccache(argc, argv);
- return 1;
}
+// 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
// 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) \
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);
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);
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);
// ----------------------------------------------------------------------------
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
// ----------------------------------------------------------------------------
-#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 *);
#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);
// 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;
}
// Wipe one cache subdirectory.
-void
+static void
wipe_dir(const char *dir)
{
cc_log("Clearing out cache directory %s", dir);
{"--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},
return retval;
}
+// Used by unittest/test_compopt.c.
+bool compopt_verify_sortedness(void);
+
// For test purposes.
bool
compopt_verify_sortedness(void)
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;
conf_item_parser parser;
size_t offset;
conf_item_verifier verifier;
+ conf_item_formatter formatter;
};
struct env_to_conf_item {
}
}
+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)
{
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)
{
}
}
+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)
{
}
}
+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)
{
*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")) {
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)
{
}
}
+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)
{
}
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
}
#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"
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;
}
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("");
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;
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);
}
}
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);
}
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;
+}
bool compression;
unsigned compression_level;
char *cpp_extension;
+ bool debug;
bool direct_mode;
bool disable;
char *extra_files_to_hash;
unsigned max_files;
uint64_t max_size;
char *path;
+ bool pch_external_checksum;
char *prefix_command;
char *prefix_command_cpp;
bool read_only;
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,
%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)
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)
#line 8 "src/confitems.gperf"
struct conf_item;
-/* maximum key range = 46, duplicates = 0 */
+/* maximum key range = 48, duplicates = 0 */
#ifdef __GNUC__
__inline
{
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]];
}
{
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)
}
return 0;
}
-static const size_t CONFITEMS_TOTAL_KEYWORDS = 31;
+static const size_t CONFITEMS_TOTAL_KEYWORDS = 33;
%%
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"
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"
/* 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) \
#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
{
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;
{
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[] =
{"",""}, {"",""},
#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"}
};
}
return 0;
}
-static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 31;
+static const size_t ENVTOCONFITEMS_TOTAL_KEYWORDS = 34;
break;
case '"':
bs = (bs << 1) + 1;
- // Fallthrough.
+ // Fallthrough.
default:
k += bs + 1;
bs = 0;
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);
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,
}
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;
+}
-// 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
}
// 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)
{
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)
+++ /dev/null
-/*
- * 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 */
// 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;
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) {
return false;
}
- bool ret = hash_fd(md, fd);
+ bool ret = hash_fd(hash, fd);
close(fd);
return ret;
}
--- /dev/null
+// 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
*/
#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/
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 *
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;
}
}
}
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;
}
POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __HASHTABLE_CWC22_H__
-#define __HASHTABLE_CWC22_H__
+#ifndef HASHTABLE_CWC22_H
+#define HASHTABLE_CWC22_H
#include "config.h"
void
hashtable_destroy(struct hashtable *h, int free_values);
-#endif /* __HASHTABLE_CWC22_H__ */
+#endif /* HASHTABLE_CWC22_H */
/*
* Copyright (c) 2002, Christopher Clark
/* 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 */
/* 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 */
-#endif /* __HASHTABLE_ITR_CWC22__*/
+#endif /* HASHTABLE_ITR_CWC22_H */
/*
* Copyright (c) 2002, 2004, Christopher Clark
/* 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"
hash(struct hashtable *h, void *k);
/*****************************************************************************/
+#ifdef HASHTABLE_INDEXFOR
/* indexFor */
static inline unsigned int
indexFor(unsigned int tablelength, unsigned int hashvalue) {
return (hashvalue & (tablelength - 1u));
}
*/
+#endif
/*****************************************************************************/
#define freekey(X) free(X)
/*****************************************************************************/
-#endif /* __HASHTABLE_PRIVATE_CWC22_H__*/
+#endif /* HASHTABLE_PRIVATE_CWC22_H */
/*
* Copyright (c) 2002, Christopher Clark
-// 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
// 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;
}
// 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
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__
// 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)) {
}
bool
-hash_command_output(struct mdfour *hash, const char *command,
+hash_command_output(struct hash *hash, const char *command,
const char *compiler)
{
#ifdef _WIN32
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) {
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]);
}
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);
+// 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
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
-// 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
#include "ccache.h"
+#include "language.h"
+
// Supported file extensions and corresponding languages (as in parameter to
// the -x option).
static const struct {
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);
}
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.
}
#define READ_BYTE(var) \
- do { \
+ do { \
int ch_ = gzgetc(f); \
if (ch_ == EOF) { \
goto error; \
} 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); \
} while (false)
#define READ_STR(var) \
- do { \
+ do { \
char buf_[1024]; \
size_t i_; \
for (i_ = 0; i_ < sizeof(buf_); i_++) { \
} while (false)
#define READ_BYTES(n, var) \
- do { \
+ do { \
for (size_t i_ = 0; i_ < (n); i_++) { \
int ch_ = gzgetc(f); \
if (ch_ == EOF) { \
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]);
}
}
#define WRITE_INT(size, var) \
- do { \
+ do { \
uint64_t u_ = (var); \
uint8_t ch_; \
size_t i_; \
} 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) { \
// 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);
}
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) {
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;
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];
// 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 {
// 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))))
#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;
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
}
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) {
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;
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) {
#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__) || \
* 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.
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
int main(void);
#endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */
-#if TEST_SNPRINTF
+#ifdef TEST_SNPRINTF
int
main(void)
{
#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)",
{
STATS_TOTALSIZE,
"cache size",
- display_size_times_1024,
+ format_size_times_1024,
FLAG_NOZERO|FLAG_ALWAYS
},
{
NULL,
FLAG_NOZERO|FLAG_NEVER
},
- {
- STATS_ZEROTIMESTAMP,
- "stats last zeroed at",
- NULL,
- FLAG_NEVER
- },
{
STATS_NONE,
NULL,
}
};
-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 *)×tamp);
+ 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.
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++) {
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)
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)) {
// 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);
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.
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) {
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);
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;
counters->data[stats_info[i].stat] = 0;
}
}
- stats_timestamp(time(NULL), counters);
+ counters->data[STATS_ZEROTIMESTAMP] = timestamp;
stats_write(fname, counters);
lockfile_release(fname);
}
// 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
// compiler (for example, inline assembly systems).
#include "ccache.h"
+#include "hash.h"
static bool print_unified = true;
// 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;
// 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 {
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++) {
// 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;
--- /dev/null
+// 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
#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) {
}
}
+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;
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
#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)
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.
}
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, ...)
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
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,
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)
}
va_end(ap);
- if (!ptr) {
- fatal("Out of memory in reformat");
- }
if (saved) {
free(saved);
}
// Default suffix: G.
x *= 1000 * 1000 * 1000;
}
- *size = x;
+ *size = (uint64_t)x;
return true;
}
// 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;
}
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);
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,
-const char CCACHE_VERSION[] = "3.4.3";
+extern const char CCACHE_VERSION[]; const char CCACHE_VERSION[] = "3.5";
# include <io.h>
#endif
-#if defined(_WIN32) || defined(__CYGWIN__)
+#if defined(_WIN32)
# define WIDECHAR
#endif
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
# define OS_CODE 13
#endif
-#if defined(WIN32) && !defined(__CYGWIN__)
+#if defined(WIN32)
# define OS_CODE 10
#endif
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
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
HOST_OS_APPLE=false
HOST_OS_LINUX=false
+HOST_OS_FREEBSD=false
HOST_OS_WINDOWS=false
compiler_version="`$COMPILER --version 2>&1 | head -1`"
*Linux*)
HOST_OS_LINUX=true
;;
+ *FreeBSD*)
+ HOST_OS_FREEBSD=true
+ ;;
esac
if $HOST_OS_WINDOWS; then
cpp1
multi_arch
serialize_diagnostics
+sanitize_blacklist
debug_prefix_map
masquerading
hardlink
# -------------------------------------------------------------------------
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
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
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
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
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
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
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
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
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
}
# =============================================================================
elif $COMPILER_TYPE_CLANG; then
cpp_flag="-frewrite-includes"
fi
- cpp_flag+=" -DBAZ=3"
+ cpp_flag="$cpp_flag -DBAZ=3"
# -------------------------------------------------------------------------
TEST "Base case"
objdump_cmd() {
if $HOST_OS_APPLE; then
xcrun dwarfdump -r0 $1
+ elif $HOST_OS_FREEBSD; then
+ objdump -W $1
else
objdump -g $1
fi
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
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
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"
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() {
--- /dev/null
+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
+}
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;
}
if (free1) {
- free((char *)expected);
+ free(expected);
}
if (free2) {
- free((char *)actual);
+ free(actual);
}
return result;
}
// ============================================================================
#define TEST_SUITE(name) \
+ unsigned suite_##name(unsigned _start_point); \
unsigned suite_##name(unsigned _start_point) \
{ \
unsigned _test_counter = 0; \
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);
#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)
{
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);
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);
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", "");
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", "");
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", "");
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", "");
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", "");
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", "");
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", "");
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", "");
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;
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", "");
TEST(option_table_should_be_sorted)
{
- bool compopt_verify_sortedness();
+ bool compopt_verify_sortedness(void);
CHECK(compopt_verify_sortedness());
}
#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;
{
(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;
}
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);
}
}
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);
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);
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);
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);
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);
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);
}
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;
8,
"ce",
false,
+ false,
true,
"efth",
true,
4711,
98.7 * 1000 * 1000,
"p",
+ true,
"pc",
"pcc",
true,
.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,
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);
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);
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);
// 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
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));
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)
}
}
+TEST(format_command)
+{
+ char *argv[] = {"foo", "bar", NULL};
+
+ CHECK_STR_EQ_FREE2("foo bar\n", format_command(argv));
+
+}
+
TEST_SUITE_END