m4/ax_code_coverage.m4
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Jul 15 11:54:06 2020 +0100 (2020-07-15)
changeset 96 d2d88f14283e
permissions -rw-r--r--
Implement file-based post configuration for pre-inst
     1 # ===========================================================================
     2 #     http://www.gnu.org/software/autoconf-archive/ax_code_coverage.html
     3 # ===========================================================================
     4 #
     5 # SYNOPSIS
     6 #
     7 #   AX_CODE_COVERAGE()
     8 #
     9 # DESCRIPTION
    10 #
    11 #   Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS,
    12 #   CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LDFLAGS which should be
    13 #   included in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LDFLAGS variables of
    14 #   every build target (program or library) which should be built with code
    15 #   coverage support. Also defines CODE_COVERAGE_RULES which should be
    16 #   substituted in your Makefile; and $enable_code_coverage which can be
    17 #   used in subsequent configure output. CODE_COVERAGE_ENABLED is defined
    18 #   and substituted, and corresponds to the value of the
    19 #   --enable-code-coverage option, which defaults to being disabled.
    20 #
    21 #   Test also for gcov program and create GCOV variable that could be
    22 #   substituted.
    23 #
    24 #   Note that all optimisation flags in CFLAGS must be disabled when code
    25 #   coverage is enabled.
    26 #
    27 #   Usage example:
    28 #
    29 #   configure.ac:
    30 #
    31 #     AX_CODE_COVERAGE
    32 #
    33 #   Makefile.am:
    34 #
    35 #     @CODE_COVERAGE_RULES@
    36 #     my_program_LIBS = ... $(CODE_COVERAGE_LDFLAGS) ...
    37 #     my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ...
    38 #     my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ...
    39 #     my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ...
    40 #
    41 #   This results in a "check-code-coverage" rule being added to any
    42 #   Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module
    43 #   has been configured with --enable-code-coverage). Running `make
    44 #   check-code-coverage` in that directory will run the module's test suite
    45 #   (`make check`) and build a code coverage report detailing the code which
    46 #   was touched, then print the URI for the report.
    47 #
    48 #   This code was derived from Makefile.decl in GLib, originally licenced
    49 #   under LGPLv2.1+.
    50 #
    51 # LICENSE
    52 #
    53 #   Copyright (c) 2012, 2016 Philip Withnall
    54 #   Copyright (c) 2012 Xan Lopez
    55 #   Copyright (c) 2012 Christian Persch
    56 #   Copyright (c) 2012 Paolo Borelli
    57 #   Copyright (c) 2012 Dan Winship
    58 #   Copyright (c) 2015 Bastien ROUCARIES
    59 #
    60 #   This library is free software; you can redistribute it and/or modify it
    61 #   under the terms of the GNU Lesser General Public License as published by
    62 #   the Free Software Foundation; either version 2.1 of the License, or (at
    63 #   your option) any later version.
    64 #
    65 #   This library is distributed in the hope that it will be useful, but
    66 #   WITHOUT ANY WARRANTY; without even the implied warranty of
    67 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
    68 #   General Public License for more details.
    69 #
    70 #   You should have received a copy of the GNU Lesser General Public License
    71 #   along with this program. If not, see <http://www.gnu.org/licenses/>.
    72 
    73 #serial 16
    74 
    75 AC_DEFUN([AX_CODE_COVERAGE],[
    76 	dnl Check for --enable-code-coverage
    77 	AC_REQUIRE([AC_PROG_SED])
    78 
    79 	# allow to override gcov location
    80 	AC_ARG_WITH([gcov],
    81 	  [AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])],
    82 	  [_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov],
    83 	  [_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov])
    84 
    85 	AC_MSG_CHECKING([whether to build with code coverage support])
    86 	AC_ARG_ENABLE([code-coverage],
    87 	  AS_HELP_STRING([--enable-code-coverage],
    88 	  [Whether to enable code coverage support]),,
    89 	  enable_code_coverage=no)
    90 
    91 	AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes])
    92 	AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage])
    93 	AC_MSG_RESULT($enable_code_coverage)
    94 
    95 	AS_IF([ test "$enable_code_coverage" = "yes" ], [
    96 		# check for gcov
    97 		AC_CHECK_TOOL([GCOV],
    98 		  [$_AX_CODE_COVERAGE_GCOV_PROG_WITH],
    99 		  [:])
   100 		AS_IF([test "X$GCOV" = "X:"],
   101 		  [AC_MSG_ERROR([gcov is needed to do coverage])])
   102 		AC_SUBST([GCOV])
   103 
   104 		dnl Check if gcc is being used
   105 		AS_IF([ test "$GCC" = "no" ], [
   106 			AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage])
   107 		])
   108 
   109 		# List of supported lcov versions.
   110 		lcov_version_list="1.6 1.7 1.8 1.9 1.10 1.11 1.12"
   111 
   112 		AC_CHECK_PROG([LCOV], [lcov], [lcov])
   113 		AC_CHECK_PROG([GENHTML], [genhtml], [genhtml])
   114 
   115 		AS_IF([ test "$LCOV" ], [
   116 			AC_CACHE_CHECK([for lcov version], ax_cv_lcov_version, [
   117 				ax_cv_lcov_version=invalid
   118 				lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'`
   119 				for lcov_check_version in $lcov_version_list; do
   120 					if test "$lcov_version" = "$lcov_check_version"; then
   121 						ax_cv_lcov_version="$lcov_check_version (ok)"
   122 					fi
   123 				done
   124 			])
   125 		], [
   126 			lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list"
   127 			AC_MSG_ERROR([$lcov_msg])
   128 		])
   129 
   130 		case $ax_cv_lcov_version in
   131 			""|invalid[)]
   132 				lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)."
   133 				AC_MSG_ERROR([$lcov_msg])
   134 				LCOV="exit 0;"
   135 			;;
   136 		esac
   137 
   138 		AS_IF([ test -z "$GENHTML" ], [
   139 			AC_MSG_ERROR([Could not find genhtml from the lcov package])
   140 		])
   141 
   142 		dnl Build the code coverage flags
   143 		CODE_COVERAGE_CPPFLAGS="-DNDEBUG"
   144 		CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
   145 		CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
   146 		CODE_COVERAGE_LDFLAGS="-lgcov"
   147 
   148 		AC_SUBST([CODE_COVERAGE_CPPFLAGS])
   149 		AC_SUBST([CODE_COVERAGE_CFLAGS])
   150 		AC_SUBST([CODE_COVERAGE_CXXFLAGS])
   151 		AC_SUBST([CODE_COVERAGE_LDFLAGS])
   152 	])
   153 
   154 [CODE_COVERAGE_RULES='
   155 # Code coverage
   156 #
   157 # Optional:
   158 #  - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting.
   159 #    Multiple directories may be specified, separated by whitespace.
   160 #    (Default: $(top_builddir))
   161 #  - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated
   162 #    by lcov for code coverage. (Default:
   163 #    $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info)
   164 #  - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage
   165 #    reports to be created. (Default:
   166 #    $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage)
   167 #  - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage,
   168 #    set to 0 to disable it and leave empty to stay with the default.
   169 #    (Default: empty)
   170 #  - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov
   171 #    instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
   172 #  - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov
   173 #    instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
   174 #  - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov
   175 #  - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the
   176 #    collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
   177 #  - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov
   178 #    instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
   179 #  - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering
   180 #    lcov instance. (Default: empty)
   181 #  - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov
   182 #    instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
   183 #  - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the
   184 #    genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
   185 #  - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml
   186 #    instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
   187 #  - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore
   188 #
   189 # The generated report will be titled using the $(PACKAGE_NAME) and
   190 # $(PACKAGE_VERSION). In order to add the current git hash to the title,
   191 # use the git-version-gen script, available online.
   192 
   193 # Optional variables
   194 CODE_COVERAGE_DIRECTORY ?= $(top_builddir)
   195 CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info
   196 CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage
   197 CODE_COVERAGE_BRANCH_COVERAGE ?=
   198 CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
   199 --rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
   200 CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
   201 CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)"
   202 CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
   203 CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
   204 CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?=
   205 CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
   206 CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\
   207 $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
   208 --rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
   209 CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULTS)
   210 CODE_COVERAGE_IGNORE_PATTERN ?=
   211 
   212 code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V))
   213 code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY))
   214 code_coverage_v_lcov_cap_0 = @echo "  LCOV   --capture"\
   215  $(CODE_COVERAGE_OUTPUT_FILE);
   216 code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V))
   217 code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY))
   218 code_coverage_v_lcov_ign_0 = @echo "  LCOV   --remove /tmp/*"\
   219  $(CODE_COVERAGE_IGNORE_PATTERN);
   220 code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V))
   221 code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY))
   222 code_coverage_v_genhtml_0 = @echo "  GEN   " $(CODE_COVERAGE_OUTPUT_DIRECTORY);
   223 code_coverage_quiet = $(code_coverage_quiet_$(V))
   224 code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY))
   225 code_coverage_quiet_0 = --quiet
   226 
   227 # sanitizes the test-name: replaces with underscores: dashes and dots
   228 code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1)))
   229 
   230 # Use recursive makes in order to ignore errors during check
   231 check-code-coverage:
   232 ifeq ($(CODE_COVERAGE_ENABLED),yes)
   233 	-$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check
   234 	$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture
   235 else
   236 	@echo "Need to reconfigure with --enable-code-coverage"
   237 endif
   238 
   239 # Capture code coverage data
   240 code-coverage-capture: code-coverage-capture-hook
   241 ifeq ($(CODE_COVERAGE_ENABLED),yes)
   242 	$(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS)
   243 	$(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS)
   244 	-@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp
   245 	$(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS)
   246 	@echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html"
   247 else
   248 	@echo "Need to reconfigure with --enable-code-coverage"
   249 endif
   250 
   251 # Hook rule executed before code-coverage-capture, overridable by the user
   252 code-coverage-capture-hook:
   253 
   254 ifeq ($(CODE_COVERAGE_ENABLED),yes)
   255 clean: code-coverage-clean
   256 distclean: code-coverage-clean
   257 code-coverage-clean:
   258 	-$(LCOV) --directory $(top_builddir) -z
   259 	-rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY)
   260 	-find . \( -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" \) -delete
   261 endif
   262 
   263 GITIGNOREFILES ?=
   264 GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY)
   265 
   266 A''M_DISTCHECK_CONFIGURE_FLAGS ?=
   267 A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage
   268 
   269 .PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean
   270 ']
   271 
   272 	AC_SUBST([CODE_COVERAGE_RULES])
   273 	m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])])
   274 ])