diff --git a/.gitignore b/.gitignore index 45e5a8d42..26e64d762 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,7 @@ /src/khost /src/knsupdate /src/knsec3hash +*.gcda +*.gcno +/*-coverage.info +/*coverage/ diff --git a/Makefile.am b/Makefile.am index 20ad25258..39c617679 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,2 +1,75 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = libtap src tests samples doc man patches + +code_coverage_quiet = $(code_coverage_quiet_$(V)) +code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY)) +code_coverage_quiet_0 = --quiet + +check-code-coverage: +if CODE_COVERAGE_ENABLED + -$(MAKE) $(AM_MAKEFLAGS) -k check + $(MAKE) $(AM_MAKEFLAGS) code-coverage-capture + $(MAKE) $(AM_MAKEFLAGS) code-coverage-html +else + @echo "You need to run configure with --enable-code-coverage to enable code coverage" +endif + +code-coverage-capture: +if CODE_COVERAGE_ENABLED + $(LCOV) $(code_coverage_quiet) \ + --directory $(top_builddir)/src/common \ + --directory $(top_builddir)/src/knot \ + --directory $(top_builddir)/src/libknot \ + --capture \ + --ignore-errors source \ + --base-directory $(top_builddir)/src \ + --output-file "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-src_capture.info" \ + --test-name "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ + --no-checksum --compat-libtool + $(LCOV) $(code_coverage_quiet) \ + --directory $(top_builddir)/src/knot/conf \ + --capture \ + --ignore-errors source \ + --base-directory $(top_builddir)/src/knot/conf \ + --output-file "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-conf_capture.info" \ + --test-name "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ + --no-checksum --compat-libtool + $(LCOV) $(code_coverage_quiet) \ + --directory $(top_builddir)/src/zscanner \ + --capture \ + --ignore-errors source \ + --base-directory $(top_builddir)/src/zscanner \ + --output-file "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-zscanner_capture.info" \ + --test-name "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ + --no-checksum --compat-libtool + $(LCOV) $(code_coverage_quiet) \ + --add-tracefile "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-src_capture.info" \ + --add-tracefile "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-conf_capture.info" \ + --add-tracefile "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-zscanner_capture.info" \ + --output-file "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info" + -@rm -f $(PACKAGE_NAME)-$(PACKAGE_VERSION)-*_base.info $(PACKAGE_NAME)-$(PACKAGE_VERSION)-*_capture.info +else + @echo "You need to run configure with --enable-code-coverage to enable code coverage" +endif + +code-coverage-html: +if CODE_COVERAGE_ENABLED + @echo "Generating code coverage HTML report (this might take a while)" + LANG=C $(GENHTML) $(code_coverage_quiet) --prefix $(top_builddir) --output-directory "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info" --ignore-errors source +else + @echo "You need to run configure with --enable-code-coverage to enable code coverage" +endif + +if CODE_COVERAGE_ENABLED +clean-local: code-coverage-clean +code-coverage-clean: + -$(LCOV) --directory $(top_builddir) -z + -rm -rf $(PACKAGE_NAME)-$(PACKAGE_VERSION)-*_base.info \ + $(PACKAGE_NAME)-$(PACKAGE_VERSION)-*_coverage.info \ + $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage/ + -find . -name "*.gcda" -o -name "*.gcov" -delete +endif + +DISTCHECK_CONFIGURE_FLAGS = --disable-code-coverage + +.PHONY: check-code-coverage code-coverage-initial code-coverage-capture code-coverage-html code-coverage-clean diff --git a/configure.ac b/configure.ac index c28e2b0dd..7666f1fce 100644 --- a/configure.ac +++ b/configure.ac @@ -355,6 +355,9 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[cpuset_t* set = cpuset #gl_VISIBILITY() #CFLAGS="$CFLAGS $CFLAG_VISIBILITY" +# Add code coverage macro +AX_CODE_COVERAGE + AC_CONFIG_FILES([Makefile doc/Makefile man/Makefile diff --git a/m4/code-coverage.m4 b/m4/code-coverage.m4 new file mode 100644 index 000000000..5b16f4cab --- /dev/null +++ b/m4/code-coverage.m4 @@ -0,0 +1,70 @@ +# Copyright 2014 CZ.NIC, z.s.p.o. +# +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 3, as published +# by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranties of +# MERCHANTABILITY, SATISFACTORY QUALITY, 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, see . + +AC_DEFUN([AX_CODE_COVERAGE], [ + dnl Check for --enable-code-coverage + AC_ARG_ENABLE([code-coverage], + AS_HELP_STRING([--enable-code-coverage], [enable code coverage testing with gcov]), + [enable_code_coverage=yes], + [enable_code_coverage=no]) + AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test "$enable_code_coverage" = "yes"]) + AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage]) + + AS_IF([test "$enable_code_coverage" = "yes"], [ + dnl Check whether gcc is used + AS_IF([test "$GCC" = "no"], [ + AC_MSG_ERROR([compiling with gcc is required for gcov code coverage]) + ]) + + AC_CHECK_PROG([LCOV], [lcov], [lcov]) + AC_CHECK_PROG([GENHTML], [genhtml], [genhtml]) + + lcov_version_list="1.6 1.7 1.8 1.9 1.10" + + AS_IF([test "$LCOV"], [ + AC_CACHE_CHECK([for lcov version], ac_cv_lvoc_version, [ + ac_cv_lcov_version=invalid + lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` + for lcov_check_version in $lcov_version_list; do + if test "$lcov_version" = "$lcov_check_version"; then + ac_cv_lcov_version="$lcov_check_version (ok)" + fi + done + ]) + ],[ + AC_MSG_ERROR([You must have one of the following lcov versions installed: $lcov_version_list to enable gcov code coverage reporting]) + ]) + + AS_CASE([$ac_cv_lcov_version], + [""|invalid], [AC_MSG_ERROR([You must have one of the following lcov versions installed: $lcov_version_list to enable gcov code coverage reporting]) + ]) + + AS_IF([test -z "$GENHTML"], [ + AC_MSG_ERROR([Could not find genhtml from the lcov package]) + ]) + + dnl Remove all optimization flags from CFLAGS + changequote({,}) + CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'` + changequote([,]) + + dnl Add the special gcc flags + CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" + CODE_COVERAGE_LDFLAGS="-lgcov" + + AC_SUBST([CODE_COVERAGE_CFLAGS]) + AC_SUBST([CODE_COVERAGE_LDFLAGS]) + ]) +]) # AC_CODE_COVERAGE diff --git a/src/Makefile.am b/src/Makefile.am index cb451fbc4..626f8ed1a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,7 +12,8 @@ AM_CPPFLAGS = \ -DCONFIG_DIR='"${config_dir}"' \ -DSTORAGE_DIR='"${storage_dir}"' \ -DRUN_DIR='"${run_dir}"' - +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_LDFLAGS = $(CODE_COVERAGE_LDFLAGS) AM_YFLAGS = -d libknotd_la_YFLAGS = -pcf_ -d libknotd_la_LFLAGS = # TODO: reentrant parser, prefix @@ -128,6 +129,7 @@ libknotus_la_SOURCES = \ # dynamic: libknot libknot_la_LDFLAGS = \ + $(CODE_COVERAGE_LDFLAGS) \ -version-info 0:1:0 \ -export-symbols-regex '^(knot|KNOT|rrset|tsig|zone)_' @@ -284,7 +286,7 @@ libknotd_la_LIBADD = libknots.la libknot.la # sbin programs knotd_LDADD = libknot.la libknotd.la knotd_CPPFLAGS = $(AM_CPPFLAGS) ${systemd_daemon_CFLAGS} -knotd_LDFLAGS = ${systemd_daemon_LIBS} +knotd_LDFLAGS = $(CODE_COVERAGE_LDFLAGS) ${systemd_daemon_LIBS} knotc_LDADD = libknot.la libknotd.la diff --git a/src/zscanner/Makefile.am b/src/zscanner/Makefile.am index 58574ee33..38bbeeacc 100644 --- a/src/zscanner/Makefile.am +++ b/src/zscanner/Makefile.am @@ -46,7 +46,9 @@ libzscanner_la_SOURCES = \ functions.h \ functions.c +libzscanner_la_CFLAGS = $(CODE_COVERAGE_CFLAGS) libzscanner_la_LDFLAGS = \ + $(COVERAGE_LDFLAGS) \ -version-info 0:1:0 \ -export-symbols-regex '^zs_'