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