1# =========================================================================== 2# https://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_LIBS which should be included 13# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every 14# 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 optimization 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_LIBS) ... 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# In earlier versions of this macro, CODE_COVERAGE_LDFLAGS was defined 49# instead of CODE_COVERAGE_LIBS. They are both still defined, but use of 50# CODE_COVERAGE_LIBS is preferred for clarity; CODE_COVERAGE_LDFLAGS is 51# deprecated. They have the same value. 52# 53# In order to generate a code coverage report across your entire project, 54# you MUST at minimum include the line: 55# 56# @CODE_COVERAGE_RULES@ 57# 58# in every single Makefile.am throughout your project. 59# 60# NOTE: If mixing non-recursive and recursive automake, then problems 61# will appear with missing source files, due to one or more LCOV base 62# directories missing. This mixed-mode will seemingly always have these 63# errors and is only solved by using recursive make OR non-recursive 64# make. 65# 66# This code was derived from Makefile.decl in GLib, originally licenced 67# under LGPLv2.1+. 68# 69# LICENSE 70# 71# Copyright (c) 2012, 2016 Philip Withnall 72# Copyright (c) 2012 Xan Lopez 73# Copyright (c) 2012 Christian Persch 74# Copyright (c) 2012 Paolo Borelli 75# Copyright (c) 2012 Dan Winship 76# Copyright (c) 2015 Bastien ROUCARIES 77# Copyright (C) 2017 Joseph Benden <joe@benden.us> 78# 79# This library is free software; you can redistribute it and/or modify it 80# under the terms of the GNU Lesser General Public License as published by 81# the Free Software Foundation; either version 2.1 of the License, or (at 82# your option) any later version. 83# 84# This library is distributed in the hope that it will be useful, but 85# WITHOUT ANY WARRANTY; without even the implied warranty of 86# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 87# General Public License for more details. 88# 89# You should have received a copy of the GNU Lesser General Public License 90# along with this program. If not, see <https://www.gnu.org/licenses/>. 91 92#serial 26 93 94AC_DEFUN([AX_CODE_COVERAGE],[ 95 dnl Check for --enable-code-coverage 96 AC_REQUIRE([AC_PROG_SED]) 97 98 # allow to override gcov location 99 AC_ARG_WITH([gcov], 100 [AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])], 101 [_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov], 102 [_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov]) 103 104 AC_MSG_CHECKING([whether to build with code coverage support]) 105 AC_ARG_ENABLE([code-coverage], 106 AS_HELP_STRING([--enable-code-coverage], 107 [Whether to enable code coverage support]),, 108 enable_code_coverage=no) 109 110 AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes]) 111 AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage]) 112 AC_MSG_RESULT($enable_code_coverage) 113 114 AS_IF([ test "$enable_code_coverage" = "yes" ], [ 115 # check for gcov 116 AC_CHECK_TOOL([GCOV], 117 [$_AX_CODE_COVERAGE_GCOV_PROG_WITH], 118 [:]) 119 AS_IF([test "X$GCOV" = "X:"], 120 [AC_MSG_ERROR([gcov is needed to do coverage])]) 121 AC_SUBST([GCOV]) 122 123 dnl Check if gcc is being used 124 AS_IF([ test "$GCC" = "no" ], [ 125 AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage]) 126 ]) 127 128 AC_CHECK_PROG([LCOV], [lcov], [lcov]) 129 AC_CHECK_PROG([GENHTML], [genhtml], [genhtml]) 130 131 AS_IF([ test -z "$LCOV" ], [ 132 AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed]) 133 ]) 134 135 AS_IF([ test -z "$GENHTML" ], [ 136 AC_MSG_ERROR([Could not find genhtml from the lcov package]) 137 ]) 138 139 dnl Build the code coverage flags 140 dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility 141 CODE_COVERAGE_CPPFLAGS="-DNDEBUG" 142 CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" 143 CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage" 144 CODE_COVERAGE_LIBS="-lgcov" 145 CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS" 146 147 AC_SUBST([CODE_COVERAGE_CPPFLAGS]) 148 AC_SUBST([CODE_COVERAGE_CFLAGS]) 149 AC_SUBST([CODE_COVERAGE_CXXFLAGS]) 150 AC_SUBST([CODE_COVERAGE_LIBS]) 151 AC_SUBST([CODE_COVERAGE_LDFLAGS]) 152 153 [CODE_COVERAGE_RULES_CHECK=' 154 $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture TOP_CODE_COVERAGE_OUTPUT_FILE="$(CODE_COVERAGE_OUTPUT_FILE)" 155 $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture TOP_CODE_COVERAGE_OUTPUT_FILE="$(CODE_COVERAGE_OUTPUT_FILE)" 156 $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-join 157 $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-remove 158 $(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-genhtml 159'] 160 [CODE_COVERAGE_RULES_CAPTURE=' 161 -$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) check-am 162 find $(builddir) \( -name "*.o" \) -exec $(GCOV) -i -b -p -r -s $(top_absdir) {} ";"; \ 163 $(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --no-recursion --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) --ignore-errors source 164 if test ! -e "$(TOP_CODE_COVERAGE_OUTPUT_FILE).join" -a -s "$(CODE_COVERAGE_OUTPUT_FILE).tmp"; then \ 165 cp -v "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "$(TOP_CODE_COVERAGE_OUTPUT_FILE).join"; \ 166 fi; 167'] 168 [CODE_COVERAGE_RULES_JOIN=' 169 find $(builddir) -size +0c -a -name "$(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info.tmp" -exec echo "\"{}\"" ";" | \ 170 xargs -L 1 $(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --no-recursion --output-file "$(CODE_COVERAGE_OUTPUT_FILE).join" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS) --ignore-errors source -a "$(CODE_COVERAGE_OUTPUT_FILE).join" -a 171'] 172 [CODE_COVERAGE_RULES_REMOVE=' 173 $(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --no-recursion --remove "$(CODE_COVERAGE_OUTPUT_FILE).join" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS) 174'] 175 [CODE_COVERAGE_RULES_GENHTML=' 176 -@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp 177 find $(top_builddir) -size 0c -a -name "*.gcov" -delete 178 $(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) --ignore-errors source 179 @echo "file://$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html" 180'] 181 [CODE_COVERAGE_RULES_CLEAN=' 182clean: code-coverage-clean 183distclean: code-coverage-clean 184code-coverage-clean: 185 -$(LCOV) --directory $(top_builddir) -z 186 -rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_FILE).join $(CODE_COVERAGE_OUTPUT_DIRECTORY) 187 -find . \( -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" \) -delete 188'] 189 ], [ 190 [CODE_COVERAGE_RULES_CHECK=' 191 @echo "Need to reconfigure with --enable-code-coverage" 192'] 193 CODE_COVERAGE_RULES_CAPTURE="$CODE_COVERAGE_RULES_CHECK" 194 CODE_COVERAGE_RULES_CLEAN='' 195 ]) 196 197[CODE_COVERAGE_RULES=' 198# Code coverage 199# 200# Optional: 201# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting. 202# Multiple directories may be specified, separated by whitespace. 203# (Default: $(top_builddir)) 204# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated 205# by lcov for code coverage. (Default: 206# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info) 207# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage 208# reports to be created. (Default: 209# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage) 210# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage, 211# set to 0 to disable it and leave empty to stay with the default. 212# (Default: empty) 213# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov 214# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) 215# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov 216# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) 217# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov 218# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the 219# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) 220# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov 221# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) 222# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering 223# lcov instance. (Default: empty) 224# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov 225# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) 226# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the 227# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE) 228# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml 229# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) 230# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore 231# 232# The generated report will be titled using the $(PACKAGE_NAME) and 233# $(PACKAGE_VERSION). In order to add the current git hash to the title, 234# use the git-version-gen script, available online. 235 236# Optional variables 237CODE_COVERAGE_DIRECTORY ?= $(builddir) 238CODE_COVERAGE_OUTPUT_FILE ?= $(abs_builddir)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info 239CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(abs_builddir)/$(PACKAGE_NAME)-coverage 240CODE_COVERAGE_BRANCH_COVERAGE ?= 1 241CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= -b $(abs_srcdir) $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ 242--rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) 243CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT) 244CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)" 245CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH) 246CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT) 247CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?= 248CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT) 249CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\ 250$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\ 251--rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE)) 252CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT) 253CODE_COVERAGE_IGNORE_PATTERN ?= 254 255GITIGNOREFILES ?= 256GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY) 257 258code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V)) 259code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY)) 260code_coverage_v_lcov_cap_0 = echo " LCOV --capture"\ 261 $(CODE_COVERAGE_OUTPUT_FILE); 262code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V)) 263code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY)) 264code_coverage_v_lcov_ign_0 = echo " LCOV --remove /tmp/*"\ 265 $(CODE_COVERAGE_IGNORE_PATTERN); 266code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V)) 267code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY)) 268code_coverage_v_genhtml_0 = echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY); 269code_coverage_quiet = $(code_coverage_quiet_$(V)) 270code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY)) 271code_coverage_quiet_0 = --quiet 272 273# sanitizes the test-name: replaces with underscores: dashes and dots 274code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1))) 275 276# Use recursive makes in order to ignore errors during check 277check-code-coverage:'"$CODE_COVERAGE_RULES_CHECK"' 278 279code-coverage-join:'"$CODE_COVERAGE_RULES_JOIN"' 280 281code-coverage-remove:'"$CODE_COVERAGE_RULES_REMOVE"' 282 283code-coverage-genhtml:'"$CODE_COVERAGE_RULES_GENHTML"' 284 285# Capture code coverage data 286#am__extra_recursive_targets = code-coverage-capture 287#am__recursive_targets += code-coverage-capture 288 289code-coverage-capture-am: code-coverage-capture-hook'"$CODE_COVERAGE_RULES_CAPTURE"' 290 291ifneq ($(SUBDIRS),) 292code-coverage-capture: code-coverage-capture-recursive 293else 294code-coverage-capture: code-coverage-capture-am 295endif 296 297# Hook rule executed before code-coverage-capture, overridable by the user 298code-coverage-capture-hook: 299 300'"$CODE_COVERAGE_RULES_CLEAN"' 301 302A''M_DISTCHECK_CONFIGURE_FLAGS ?= 303A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage 304 305# .PHONY: check-code-coverage code-coverage-capture code-coverage-capture-recursive code-coverage-capture-am code-coverage-join code-coverage-remove code-coverage-genhtml code-coverage-capture-hook code-coverage-clean 306.MAKE: code-coverage-capture-am 307 308.PHONY: code-coverage-capture-am code-coverage-capture \ 309 check-code-coverage code-coverage-join code-coverage-remove code-coverage-genhtml code-coverage-capture-hook code-coverage-clean 310 311'] 312 313 am__extra_recursive_targets="code-coverage-capture-recursive" 314 AC_SUBST([am__extra_recursive_targets]) 315 AC_SUBST([CODE_COVERAGE_RULES]) 316 m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])]) 317]) 318