From 181c21abd4912431e58d9ea6bd6a3027686db6ec Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 2 Feb 2011 16:51:30 +0000 Subject: [PATCH 2/2] Import compiler.m4 and lcov.am from telepathy-glib, and use them to replace gcov --- .gitignore | 5 + HACKING | 6 +- Makefile.am | 42 +- README | 2 +- cmake/test/CMakeLists.txt | 7 - configure.in | 36 +- m4/compiler.m4 | 67 ++ test/Makefile.am | 13 +- test/decode-gcov.c | 2653 --------------------------------------------- tools/lcov.am | 46 + 10 files changed, 129 insertions(+), 2748 deletions(-) create mode 100644 m4/compiler.m4 delete mode 100644 test/decode-gcov.c create mode 100644 tools/lcov.am diff --git a/.gitignore b/.gitignore index d5e84b7..db3db97 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,11 @@ config.h.in *.bbg *.da *.gcov +*.gcda +*.gcno tags /dbus-1.*/ /dbus-1.*.tar.* +/lcov.html/ +/lcov.info +/lcov.info.tmp diff --git a/HACKING b/HACKING index 442508a..2e41715 100644 --- a/HACKING +++ b/HACKING @@ -289,10 +289,8 @@ is to add a test in here. "make check" runs all the deterministic test programs (i.e. not break-loader). -"make check-coverage" is available if you configure with --enable-gcov and -gives a complete report on test suite coverage. You can also run -"test/decode-gcov foo.c" on any source file to get annotated source, -after running make check with a gcov-enabled tree. +"make lcov-check" is available if you configure with --enable-compiler-coverage +and gives a complete report on test suite coverage. Patches === diff --git a/Makefile.am b/Makefile.am index 2ce25d5..ac7dcb1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,46 +23,6 @@ EXTRA_DIST = \ all-local: Doxyfile -if DBUS_GCOV_ENABLED -clean-gcov: - find -name "*.da" -o -name "*.gcov" | xargs rm || true - -clean-bbg: - find -name "*.bbg" -o -name "*.bb" | xargs rm || true - -GCOV_DIRS=dbus bus - -## .PHONY so it always rebuilds it -.PHONY: coverage-report.txt -coverage-report.txt: - BBG_FILES=`find $(GCOV_DIRS) -name "*.bbg" -o -name "*.gcno"` ; \ - C_FILES= ; \ - for F in $$BBG_FILES ; do \ - F_nolibs=`echo $$F | sed -e 's/.libs\///g'` ; \ - C=`echo $$F_nolibs | sed -e 's/.bbg/.c/g' | sed -e 's/.gcno/.c/g'` ; \ - B=`basename $$F .bbg` ; \ - D=`dirname $$F` ; \ - DA=`echo $$F | sed -e 's/.bbg/.da/g'` ; \ - DA_libs=`echo $$D/.libs/$$B/.da` ; \ - if test -e $$DA || test -e $$DA_libs; then \ - C_FILES="$$C_FILES $$C" ; \ - fi ; \ - done ; \ - echo $$C_FILES ; \ - $(top_builddir)/test/decode-gcov --report $$C_FILES > coverage-report.txt - -check-coverage: clean-gcov all check coverage-report.txt - cat coverage-report.txt - -else -coverage-report.txt: - echo "Need to reconfigure with --enable-gcov" - -check-coverage: - echo "Need to reconfigure with --enable-gcov" - -endif - update-authors: git shortlog -s -e | cut -c 8- | sort > AUTHORS @@ -70,3 +30,5 @@ DISTCHECK_CONFIGURE_FLAGS = \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) ACLOCAL_AMFLAGS = -I m4 + +include tools/lcov.am diff --git a/README b/README index 89bfaf7..be4aede 100644 --- a/README +++ b/README @@ -83,7 +83,7 @@ the ./configure program are these --enable-checks include sanity checks on public API --enable-xml-docs build XML documentation (requires xmlto) --enable-doxygen-docs build DOXYGEN documentation (requires Doxygen) - --enable-gcov compile with coverage profiling instrumentation (gcc only) + --enable-compiler-coverage compile with coverage profiling instrumentation (gcc only) --enable-abstract-sockets use abstract socket namespace (linux only) --enable-selinux build with SELinux support --enable-dnotify build with dnotify support (linux only) diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt index 7bb80ab..9a259d2 100644 --- a/cmake/test/CMakeLists.txt +++ b/cmake/test/CMakeLists.txt @@ -52,10 +52,6 @@ set (test-sleep-forever_SOURCES ${CMAKE_SOURCE_DIR}/../test/test-sleep-forever.c ) -set (decode_gcov_SOURCES - ${CMAKE_SOURCE_DIR}/../test/decode-gcov.c -) - add_executable(test-service ${test-service_SOURCES}) target_link_libraries(test-service ${DBUS_INTERNAL_LIBRARIES}) @@ -81,9 +77,6 @@ target_link_libraries(test-segfault ${DBUS_INTERNAL_LIBRARIES}) add_executable(test-sleep-forever ${test-sleep-forever_SOURCES}) target_link_libraries(test-sleep-forever ${DBUS_INTERNAL_LIBRARIES}) -#add_executable(decode-gcov ${decode_gcov_SOURCES}) -#target_link_libraries(decode-gcov ${DBUS_INTERNAL_LIBRARIES}) - ### keep these in creation order, i.e. uppermost dirs first set (TESTDIRS test/data diff --git a/configure.in b/configure.in index 50a0a14..5967ef1 100644 --- a/configure.in +++ b/configure.in @@ -71,6 +71,8 @@ AC_HEADER_STDC AC_C_INLINE AM_PROG_LIBTOOL AC_PROG_MKDIR_P +COMPILER_COVERAGE +COMPILER_OPTIMISATIONS # Set some internal variables depending on the platform for later use. dbus_win=no @@ -128,7 +130,6 @@ AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion chec AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes) AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([--enable-xml-docs],[build XML documentation (requires xmlto)]),enable_xml_docs=$enableval,enable_xml_docs=auto) AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto) -AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),enable_gcov=$enableval,enable_gcov=no) AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto) AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto) AC_ARG_ENABLE(libaudit,AS_HELP_STRING([--enable-libaudit],[build audit daemon support for SELinux]),enable_libaudit=$enableval,enable_libaudit=auto) @@ -188,20 +189,10 @@ if test x$enable_userdb_cache = xyes; then AC_DEFINE(DBUS_ENABLE_USERDB_CACHE,1,[Build with caching of user data]) fi -if test x$enable_gcov = xyes; then +if test x$enable_compiler_coverage = xyes; then ## so that config.h changes when you toggle gcov support AC_DEFINE_UNQUOTED(DBUS_GCOV_ENABLED, 1, [Defined if gcov is enabled to force a rebuild due to config.h changing]) - - AC_MSG_CHECKING([for gcc 3.3 version of gcov file format]) - have_gcc33_gcov=no - AC_RUN_IFELSE( [AC_LANG_PROGRAM( , [[ if (__GNUC__ >=3 && __GNUC_MINOR__ >= 3) exit (0); else exit (1); ]])], - have_gcc33_gcov=yes) - if test x$have_gcc33_gcov = xyes ; then - AC_DEFINE_UNQUOTED(DBUS_HAVE_GCC33_GCOV, 1, [Defined if we have gcc 3.3 and thus the new gcov format]) - fi - AC_MSG_RESULT($have_gcc33_gcov) fi -AM_CONDITIONAL(DBUS_GCOV_ENABLED, test x$enable_gcov = xyes) # glibc21.m4 serial 3 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. @@ -1281,24 +1272,7 @@ if test "x$GCC" = "xyes"; then *) CFLAGS="$CFLAGS -pedantic" ;; esac fi - if test x$enable_gcov = xyes; then - case " $CFLAGS " in - *[\ \ ]-fprofile-arcs[\ \ ]*) ;; - *) CFLAGS="$CFLAGS -fprofile-arcs" ;; - esac - case " $CFLAGS " in - *[\ \ ]-ftest-coverage[\ \ ]*) ;; - *) CFLAGS="$CFLAGS -ftest-coverage" ;; - esac - - ## remove optimization - CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9]*//g'` - fi changequote([,])dnl -else - if test x$enable_gcov = xyes; then - AC_MSG_ERROR([--enable-gcov can only be used with gcc]) - fi fi AC_SUBST(PIC_CFLAGS) @@ -1690,7 +1664,7 @@ echo " echo " Maintainer mode: ${USE_MAINTAINER_MODE} - gcc coverage profiling: ${enable_gcov} + gcc coverage profiling: ${enable_compiler_coverage} Building unit tests: ${enable_tests} Building verbose mode: ${enable_verbose_mode} Building assertions: ${enable_asserts} @@ -1729,7 +1703,7 @@ fi if test x$enable_tests = xyes -a x$enable_asserts = xno; then echo "NOTE: building with unit tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)" fi -if test x$enable_gcov = xyes; then +if test x$enable_compiler_coverage = xyes; then echo "NOTE: building with coverage profiling is definitely for developers only." fi if test x$enable_verbose_mode = xyes; then diff --git a/m4/compiler.m4 b/m4/compiler.m4 new file mode 100644 index 0000000..5aff5d8 --- /dev/null +++ b/m4/compiler.m4 @@ -0,0 +1,67 @@ +# compiler.m4 - autoconf macros for compiler settings +# +# Copyright © 2005 Scott James Remnant . +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +# COMPILER_WARNINGS +# ---------------------- +# Add configure option to enable additional compiler warnings and treat +# them as errors. +AC_DEFUN([COMPILER_WARNINGS], +[AC_ARG_ENABLE(compiler-warnings, + AS_HELP_STRING([--enable-compiler-warnings], + [Enable additional compiler warnings]), +[if test "x$enable_compiler_warnings" = "xyes"; then + if test "x$GCC" = "xyes"; then + CFLAGS="-Wall -Werror $CFLAGS" + fi + if test "x$GXX" = "xyes"; then + CXXFLAGS="-Wall -Werror $CXXFLAGS" + fi +fi])dnl +])# COMPILER_WARNINGS + +# COMPILER_OPTIMISATIONS +# --------------------------- +# Add configure option to disable optimisations. +AC_DEFUN([COMPILER_OPTIMISATIONS], +[AC_ARG_ENABLE(compiler-optimisations, + AS_HELP_STRING([--disable-compiler-optimisations], + [Disable compiler optimisations]), +[if test "x$enable_compiler_optimisations" = "xno"; then + [CFLAGS=`echo "$CFLAGS" | sed -e "s/ -O[1-9]*\b/ -O0/g"`] +fi])dnl +])# COMPILER_OPTIMISATIONS + +# COMPILER_COVERAGE +# ---------------------- +# Add configure option to enable coverage data. +AC_DEFUN([COMPILER_COVERAGE], +[AC_ARG_ENABLE(compiler-coverage, + AS_HELP_STRING([--enable-compiler-coverage], + [Enable generation of coverage data]), +[if test "x$enable_compiler_coverage" = "xyes"; then + if test "x$GCC" = "xyes"; then + CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage" + fi +fi])dnl +])# COMPILER_COVERAGE diff --git a/test/Makefile.am b/test/Makefile.am index 110e5dc..9d0681b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -23,13 +23,7 @@ TEST_BINARIES= TESTS= endif -if DBUS_GCOV_ENABLED -GCOV_BINARIES=decode-gcov -else -GCOV_BINARIES= -endif - -noinst_PROGRAMS= $(TEST_BINARIES) $(GCOV_BINARIES) +noinst_PROGRAMS= $(TEST_BINARIES) test_service_SOURCES= \ test-service.c @@ -58,9 +52,6 @@ test_segfault_SOURCES = \ test_sleep_forever_SOURCES = \ test-sleep-forever.c -decode_gcov_SOURCES= \ - decode-gcov.c - # When any programs are not linked to libdbus-internal, fix this. AM_CPPFLAGS=-DDBUS_STATIC_BUILD TEST_LIBS=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS) @@ -77,8 +68,6 @@ shell_test_LDADD=libdbus-testutils.la $(TEST_LIBS) shell_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ spawn_test_LDADD=$(TEST_LIBS) spawn_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ -decode_gcov_LDADD=$(TEST_LIBS) -decode_gcov_LDFLAGS=@R_DYNAMIC_LDFLAG@ EXTRA_DIST= diff --git a/test/decode-gcov.c b/test/decode-gcov.c deleted file mode 100644 index 3b2a152..0000000 --- a/test/decode-gcov.c +++ /dev/null @@ -1,2653 +0,0 @@ - /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* decode-gcov.c gcov decoder program - * - * Copyright (C) 2003 Red Hat Inc. - * - * Partially derived from gcov, - * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, - * 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - * - * This file is NOT licensed under the Academic Free License - * as it is largely derived from gcov.c and gcov-io.h in the - * gcc source code. - * - * 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 2 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 - * - */ - -#include -#define DBUS_COMPILATION /* cheat */ -#include -#include -#include -#include -#include -#undef DBUS_COMPILATION -#include -#include -#include - -#ifndef DBUS_HAVE_INT64 -#error "gcov support can't be built without 64-bit integer support" -#endif - -static void -die (const char *message) -{ - fprintf (stderr, "%s", message); - exit (1); -} - -/* This bizarro function is from gcov-io.h in gcc source tree */ -static int -fetch_long (long *dest, - const char *source, - size_t bytes) -{ - long value = 0; - int i; - - for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--) - if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 )) - return 1; - - for (; i >= 0; i--) - value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255)); - - if ((source[bytes - 1] & 128) && (value > 0)) - value = - value; - - *dest = value; - return 0; -} - -static int -fetch_long64 (dbus_int64_t *dest, - const char *source, - size_t bytes) -{ - dbus_int64_t value = 0; - int i; - - for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--) - if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 )) - return 1; - - for (; i >= 0; i--) - value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255)); - - if ((source[bytes - 1] & 128) && (value > 0)) - value = - value; - - *dest = value; - return 0; -} - -#define BB_FILENAME (-1) -#define BB_FUNCTION (-2) -#define BB_ENDOFLIST 0 - -static dbus_bool_t -string_get_int (const DBusString *str, - int start, - long *val) -{ - const char *p; - - if ((_dbus_string_get_length (str) - start) < 4) - return FALSE; - - p = _dbus_string_get_const_data (str); - - p += start; - - fetch_long (val, p, 4); - - return TRUE; -} - -static dbus_bool_t -string_get_int64 (const DBusString *str, - int start, - dbus_int64_t *val) -{ - const char *p; - - if ((_dbus_string_get_length (str) - start) < 8) - return FALSE; - - p = _dbus_string_get_const_data (str); - - p += start; - - fetch_long64 (val, p, 8); - - return TRUE; -} - -static dbus_bool_t -string_get_string (const DBusString *str, - int start, - long terminator, - DBusString *val, - int *end) -{ - int i; - long n; - - i = start; - while (string_get_int (str, i, &n)) - { - unsigned char b; - - i += 4; - - if (n == terminator) - break; - - b = n & 0xff; - if (b) - { - _dbus_string_append_byte (val, b); - b = (n >> 8) & 0xff; - if (b) - { - _dbus_string_append_byte (val, b); - b = (n >> 16) & 0xff; - if (b) - { - _dbus_string_append_byte (val, b); - b = (n >> 24) & 0xff; - if (b) - _dbus_string_append_byte (val, b); - } - } - } - } - - *end = i; - - return TRUE; -} - -#ifdef DBUS_HAVE_GCC33_GCOV -/* In gcc33 .bbg files, there's a function name of the form: - * -1, length, name (padded to 4), -1, checksum - */ -static dbus_bool_t -string_get_function (const DBusString *str, - int start, - DBusString *funcname, - int *checksum, - int *next) -{ - int end; - long val; - int i; - - i = start; - - if (!string_get_int (str, i, &val)) - die ("no room for -1 before function name\n"); - - i += 4; - - if (val != -1) - die ("value before function name is not -1\n"); - - if (!string_get_int (str, i, &val)) - die ("no length found for function name\n"); - - i += 4; - - end = i + val; - if (end > _dbus_string_get_length (str)) - die ("Function name length points past end of file\n"); - - if (!_dbus_string_append (funcname, - _dbus_string_get_const_data (str) + i)) - die ("no memory\n"); - - /* skip alignment padding the length doesn't include the nul so add 1 - */ - i = _DBUS_ALIGN_VALUE (end + 1, 4); - - if (!string_get_int (str, i, &val) || - val != -1) - die ("-1 at end of function name not found\n"); - - i += 4; - - if (!string_get_int (str, i, &val)) - die ("no checksum found at end of function name\n"); - - i += 4; - - *checksum = val; - - *next = i; - - return TRUE; -} -#endif /* DBUS_HAVE_GCC33_GCOV */ - -static void -dump_bb_file (const DBusString *contents) -{ - int i; - long val; - int n_functions; - - n_functions = 0; - i = 0; - while (string_get_int (contents, i, &val)) - { - i += 4; - - switch (val) - { - case BB_FILENAME: - { - DBusString f; - - if (!_dbus_string_init (&f)) - die ("no memory\n"); - - if (string_get_string (contents, i, - BB_FILENAME, - &f, &i)) - { - printf ("File %s\n", _dbus_string_get_const_data (&f)); - } - _dbus_string_free (&f); - } - break; - case BB_FUNCTION: - { - DBusString f; - if (!_dbus_string_init (&f)) - die ("no memory\n"); - - if (string_get_string (contents, i, - BB_FUNCTION, - &f, &i)) - { - printf ("Function %s\n", _dbus_string_get_const_data (&f)); - } - _dbus_string_free (&f); - - n_functions += 1; - } - break; - case BB_ENDOFLIST: - printf ("End of block\n"); - break; - default: - printf ("Line %ld\n", val); - break; - } - } - - printf ("%d functions in file\n", n_functions); -} - -#define FLAG_ON_TREE 0x1 -#define FLAG_FAKE 0x2 -#define FLAG_FALL_THROUGH 0x4 - -static void -dump_bbg_file (const DBusString *contents) -{ - int i; - long val; - int n_functions; - int n_arcs; - int n_blocks; - int n_arcs_off_tree; - - n_arcs_off_tree = 0; - n_blocks = 0; - n_arcs = 0; - n_functions = 0; - i = 0; - while (i < _dbus_string_get_length (contents)) - { - long n_blocks_in_func; - long n_arcs_in_func; - int j; - -#ifdef DBUS_HAVE_GCC33_GCOV - /* In gcc33 .bbg files, there's a function name of the form: - * -1, length, name (padded to 4), -1, checksum - * after that header on each function description, it's - * the same as in gcc32 - */ - - { - DBusString funcname; - int checksum; - - if (!_dbus_string_init (&funcname)) - die ("no memory\n"); - - if (!string_get_function (contents, i, - &funcname, &checksum, &i)) - die ("could not read function name\n"); - - printf ("Function name is \"%s\" checksum %d\n", - _dbus_string_get_const_data (&funcname), - checksum); - - _dbus_string_free (&funcname); - } -#endif /* DBUS_HAVE_GCC33_GCOV */ - - if (!string_get_int (contents, i, &val)) - die ("no count of blocks in func found\n"); - - i += 4; - - n_blocks_in_func = val; - - if (!string_get_int (contents, i, &n_arcs_in_func)) - break; - - i += 4; - - printf ("Function has %ld blocks and %ld arcs\n", - n_blocks_in_func, n_arcs_in_func); - - n_functions += 1; - n_blocks += n_blocks_in_func; - n_arcs += n_arcs_in_func; - - j = 0; - while (j < n_blocks_in_func) - { - long n_arcs_in_block; - int k; - - if (!string_get_int (contents, i, &n_arcs_in_block)) - break; - - i += 4; - - printf (" Block has %ld arcs\n", n_arcs_in_block); - - k = 0; - while (k < n_arcs_in_block) - { - long destination_block; - long flags; - - if (!string_get_int (contents, i, &destination_block)) - break; - - i += 4; - - if (!string_get_int (contents, i, &flags)) - break; - - i += 4; - - printf (" Arc has destination block %ld flags 0x%lx\n", - destination_block, flags); - - if ((flags & FLAG_ON_TREE) == 0) - n_arcs_off_tree += 1; - - ++k; - } - - if (k < n_arcs_in_block) - break; - - ++j; - } - - if (j < n_blocks_in_func) - break; - - if (!string_get_int (contents, i, &val)) - break; - - i += 4; - - if (val != -1) - die ("-1 separator not found\n"); - } - - printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n", - n_functions, n_blocks, n_arcs, n_arcs_off_tree); -} - -#ifndef DBUS_HAVE_GCC33_GCOV - -/* gcc 3.2 version: - * The da file contains first a count of arcs in the file, - * then a count of executions for all "off tree" arcs - * in the file. - */ -static void -dump_da_file (const DBusString *contents) -{ - int i; - dbus_int64_t val; - int n_arcs; - int claimed_n_arcs; - - i = 0; - if (!string_get_int64 (contents, i, &val)) - return; - - i += 8; - - printf ("%ld arcs in file\n", (long) val); - claimed_n_arcs = val; - - n_arcs = 0; - while (string_get_int64 (contents, i, &val)) - { - i += 8; - - printf ("%ld executions of arc %d\n", - (long) val, n_arcs); - - ++n_arcs; - } - - if (n_arcs != claimed_n_arcs) - { - printf ("File claimed to have %d arcs but only had %d\n", - claimed_n_arcs, n_arcs); - } -} - -#else /* DBUS_HAVE_GCC33_GCOV */ - -/* gcc 3.3 version: - * The da file is more complex than 3.2. - * - * We have a magic value of "-123" only it isn't really - * -123, it's -123 as encoded by the crackass gcov-io.h - * routines. Anyway, 4 bytes. - * - * We then have: - * - * - 4 byte count of how many functions in the following list - * - 4 byte length of random extra data - * - the random extra data, just skip it, info pages have some - * details on what might be in there or see __bb_exit_func in gcc - * - then for each function (number of functions given above): - * . -1, length, funcname, alignment padding, -1 - * . checksum - * . 4 byte number of arcs in function - * . 8 bytes each, a count of execution for each arc - * - * Now, the whole thing *starting with the magic* can repeat. - * This is caused by multiple runs of the profiled app appending - * to the file. - */ -static void -dump_da_file (const DBusString *contents) -{ - int i; - dbus_int64_t v64; - long val; - int n_sections; - int total_functions; - - total_functions = 0; - n_sections = 0; - - i = 0; - while (i < _dbus_string_get_length (contents)) - { - int claimed_n_functions; - int n_functions; - int total_arcs; - - printf (".da file section %d\n", n_sections); - - if (!string_get_int (contents, i, &val)) - die ("no magic found in .da file\n"); - - i += 4; - - if (val != -123) - die ("wrong file magic in .da file\n"); - - if (!string_get_int (contents, i, &val)) - die ("no function count in .da file\n"); - i += 4; - claimed_n_functions = val; - - printf ("%d functions expected in section %d of .da file\n", - claimed_n_functions, n_sections); - - if (!string_get_int (contents, i, &val)) - die ("no extra data length in .da file\n"); - - i += 4; - - i += val; - - total_arcs = 0; - n_functions = 0; - while (n_functions < claimed_n_functions) - { - DBusString funcname; - int checksum; - int claimed_n_arcs; - int n_arcs; - - if (!_dbus_string_init (&funcname)) - die ("no memory\n"); - - if (!string_get_function (contents, i, - &funcname, &checksum, &i)) - die ("could not read function name\n"); - - if (!string_get_int (contents, i, &val)) - die ("no arc count for function\n"); - - i += 4; - claimed_n_arcs = val; - - printf (" %d arcs in function %d %s checksum %d\n", - claimed_n_arcs, n_functions, - _dbus_string_get_const_data (&funcname), - checksum); - - n_arcs = 0; - while (n_arcs < claimed_n_arcs) - { - if (!string_get_int64 (contents, i, &v64)) - die ("did not get execution count for arc\n"); - - i += 8; - - printf (" %ld executions of arc %d (total arcs %d)\n", - (long) v64, n_arcs, total_arcs + n_arcs); - - ++n_arcs; - } - - _dbus_string_free (&funcname); - - total_arcs += n_arcs; - ++n_functions; - } - - printf ("total of %d functions and %d arcs in section %d\n", - n_functions, total_arcs, n_sections); - - total_functions += n_functions; - ++n_sections; - } - - printf ("%d total function sections in %d total .da file sections\n", - total_functions, n_sections); -} - -#endif /* DBUS_HAVE_GCC33_GCOV */ - -typedef struct Arc Arc; -typedef struct Block Block; -typedef struct Function Function; -typedef struct File File; -typedef struct Line Line; - -struct Arc -{ - int source; - int target; - dbus_int64_t arc_count; - unsigned int count_valid : 1; - unsigned int on_tree : 1; - unsigned int fake : 1; - unsigned int fall_through : 1; - Arc *pred_next; - Arc *succ_next; -}; - -struct Block -{ - Arc *succ; - Arc *pred; - dbus_int64_t succ_count; - dbus_int64_t pred_count; - dbus_int64_t exec_count; - DBusList *lines; - unsigned int count_valid : 1; - unsigned int on_tree : 1; - unsigned int inside_dbus_build_tests : 1; -}; - -struct Function -{ - char *name; - int checksum; - Block *block_graph; - int n_blocks; - /* number of blocks in DBUS_BUILD_TESTS */ - int n_test_blocks; - int n_test_blocks_executed; - /* number of blocks outside DBUS_BUILD_TESTS */ - int n_nontest_blocks; - int n_nontest_blocks_executed; - /* Summary result flags */ - unsigned int unused : 1; - unsigned int inside_dbus_build_tests : 1; - unsigned int partial : 1; /* only some of the blocks were executed */ -}; - -struct Line -{ - int number; - char *text; - DBusList *blocks; - unsigned int inside_dbus_build_tests : 1; - unsigned int partial : 1; /* only some of the blocks were executed */ -}; - -struct File -{ - char *name; - Line *lines; - int n_lines; - DBusList *functions; -}; - -static void -function_add_arc (Function *function, - long source, - long target, - long flags) -{ - Arc *arc; - - arc = dbus_new0 (Arc, 1); - if (arc == NULL) - die ("no memory\n"); - - arc->target = target; - arc->source = source; - - arc->succ_next = function->block_graph[source].succ; - function->block_graph[source].succ = arc; - function->block_graph[source].succ_count += 1; - - arc->pred_next = function->block_graph[target].pred; - function->block_graph[target].pred = arc; - function->block_graph[target].pred_count += 1; - - if ((flags & FLAG_ON_TREE) != 0) - arc->on_tree = TRUE; - - if ((flags & FLAG_FAKE) != 0) - arc->fake = TRUE; - - if ((flags & FLAG_FALL_THROUGH) != 0) - arc->fall_through = TRUE; -} - - -static Arc* -reverse_arcs (Arc *arc) -{ - struct Arc *prev = 0; - struct Arc *next; - - for ( ; arc; arc = next) - { - next = arc->succ_next; - arc->succ_next = prev; - prev = arc; - } - - return prev; -} - -static void -function_reverse_succ_arcs (Function *func) -{ - /* Must reverse the order of all succ arcs, to ensure that they match - * the order of the data in the .da file. - */ - int i; - - for (i = 0; i < func->n_blocks; i++) - if (func->block_graph[i].succ) - func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ); -} - -static void -get_functions_from_bbg (const DBusString *contents, - DBusList **functions) -{ - int i; - long val; - int n_functions; - int n_arcs; - int n_blocks; - int n_arcs_off_tree; - -#if 0 - printf ("Loading arcs and blocks from .bbg file\n"); -#endif - - n_arcs_off_tree = 0; - n_blocks = 0; - n_arcs = 0; - n_functions = 0; - i = 0; - while (i < _dbus_string_get_length (contents)) - { - Function *func; - long n_blocks_in_func; - long n_arcs_in_func; - int j; - -#ifdef DBUS_HAVE_GCC33_GCOV - DBusString funcname; - int checksum; - - /* In gcc33 .bbg files, there's a function name of the form: - * -1, length, name (padded to 4), -1, checksum - * after that header on each function description, it's - * the same as in gcc32 - */ - if (!_dbus_string_init (&funcname)) - die ("no memory\n"); - - if (!string_get_function (contents, i, - &funcname, &checksum, &i)) - die ("could not read function name\n"); -#endif /* DBUS_HAVE_GCC33_GCOV */ - - if (!string_get_int (contents, i, &val)) - break; - - n_blocks_in_func = val; - - i += 4; - - if (!string_get_int (contents, i, &n_arcs_in_func)) - break; - - i += 4; - - n_functions += 1; - n_blocks += n_blocks_in_func; - n_arcs += n_arcs_in_func; - - func = dbus_new0 (Function, 1); - if (func == NULL) - die ("no memory\n"); - -#ifdef DBUS_HAVE_GCC33_GCOV - func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname)); - func->checksum = checksum; - _dbus_string_free (&funcname); -#endif - - func->block_graph = dbus_new0 (Block, n_blocks_in_func); - func->n_blocks = n_blocks_in_func; - - j = 0; - while (j < n_blocks_in_func) - { - long n_arcs_in_block; - int k; - - if (!string_get_int (contents, i, &n_arcs_in_block)) - break; - - i += 4; - - k = 0; - while (k < n_arcs_in_block) - { - long destination_block; - long flags; - - if (!string_get_int (contents, i, &destination_block)) - break; - - i += 4; - - if (!string_get_int (contents, i, &flags)) - break; - - i += 4; - - if ((flags & FLAG_ON_TREE) == 0) - n_arcs_off_tree += 1; - - function_add_arc (func, j, destination_block, - flags); - - ++k; - } - - if (k < n_arcs_in_block) - break; - - ++j; - } - - if (j < n_blocks_in_func) - break; - - function_reverse_succ_arcs (func); - - if (!_dbus_list_append (functions, func)) - die ("no memory\n"); - - if (!string_get_int (contents, i, &val)) - break; - - i += 4; - - if (val != -1) - die ("-1 separator not found in .bbg file\n"); - } - -#if 0 - printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n", - n_functions, n_blocks, n_arcs, n_arcs_off_tree); -#endif - - _dbus_assert (n_functions == _dbus_list_get_length (functions)); -} - -#ifdef DBUS_HAVE_GCC33_GCOV -static void -add_counts_from_da (const DBusString *contents, - DBusList **functions) -{ - int i; - dbus_int64_t v64; - long val; - int n_sections; - DBusList *link; - Function *current_func; - int current_block; - Arc *current_arc; - - n_sections = 0; - - i = 0; - while (i < _dbus_string_get_length (contents)) - { - int claimed_n_functions; - int n_functions; - - if (!string_get_int (contents, i, &val)) - die ("no magic found in .da file\n"); - - i += 4; - - if (val != -123) - die ("wrong file magic in .da file\n"); - - if (!string_get_int (contents, i, &val)) - die ("no function count in .da file\n"); - i += 4; - claimed_n_functions = val; - - if (!string_get_int (contents, i, &val)) - die ("no extra data length in .da file\n"); - - i += 4; - - i += val; - - link = _dbus_list_get_first_link (functions); - if (link == NULL) - goto no_more_functions; - - n_functions = 0; - while (n_functions < claimed_n_functions && link != NULL) - { - DBusString funcname; - int checksum; - int claimed_n_arcs; - int n_arcs; - - current_func = link->data; - current_block = 0; - current_arc = current_func->block_graph[current_block].succ; - - if (!_dbus_string_init (&funcname)) - die ("no memory\n"); - - if (!string_get_function (contents, i, - &funcname, &checksum, &i)) - die ("could not read function name\n"); - - if (!_dbus_string_equal_c_str (&funcname, current_func->name)) - { - fprintf (stderr, "Expecting .da info for %s but got %s\n", - current_func->name, - _dbus_string_get_const_data (&funcname)); - exit (1); - } - - if (checksum != current_func->checksum) - die (".da file checksum doesn't match checksum from .bbg file\n"); - - if (!string_get_int (contents, i, &val)) - die ("no arc count for function\n"); - - i += 4; - claimed_n_arcs = val; - - /* For each arc in the profile, find the corresponding - * arc in the function and increment its count - */ - n_arcs = 0; - while (n_arcs < claimed_n_arcs) - { - if (!string_get_int64 (contents, i, &v64)) - die ("did not get execution count for arc\n"); - - i += 8; - - /* Find the next arc in the function that isn't on tree */ - while (current_arc == NULL || - current_arc->on_tree) - { - if (current_arc == NULL) - { - ++current_block; - - if (current_block >= current_func->n_blocks) - die ("too many blocks in function\n"); - - current_arc = current_func->block_graph[current_block].succ; - } - else - { - current_arc = current_arc->succ_next; - } - } - - _dbus_assert (current_arc != NULL); - _dbus_assert (!current_arc->on_tree); - - current_arc->arc_count = v64; - current_arc->count_valid = TRUE; - current_func->block_graph[current_block].succ_count -= 1; - current_func->block_graph[current_arc->target].pred_count -= 1; - - ++n_arcs; - - current_arc = current_arc->succ_next; - } - - _dbus_string_free (&funcname); - - link = _dbus_list_get_next_link (functions, link); - ++n_functions; - - if (link == NULL && n_functions < claimed_n_functions) - { - fprintf (stderr, "Ran out of functions loading .da file\n"); - goto no_more_functions; - } - } - - no_more_functions: - - ++n_sections; - } -} -#else /* DBUS_HAVE_GCC33_GCOV */ -static void -add_counts_from_da (const DBusString *contents, - DBusList **functions) -{ - int i; - dbus_int64_t val; - int n_arcs; - int claimed_n_arcs; - DBusList *link; - Function *current_func; - int current_block; - Arc *current_arc; - -#if 0 - printf ("Loading execution count for each arc from .da file\n"); -#endif - - i = 0; - if (!string_get_int64 (contents, i, &val)) - return; - - i += 8; - - claimed_n_arcs = val; - - link = _dbus_list_get_first_link (functions); - if (link == NULL) - goto done; - - current_func = link->data; - current_block = 0; - current_arc = current_func->block_graph[current_block].succ; - - n_arcs = 0; - while (string_get_int64 (contents, i, &val)) - { - i += 8; - - while (current_arc == NULL || - current_arc->on_tree) - { - if (current_arc == NULL) - { - ++current_block; - - if (current_block == current_func->n_blocks) - { - link = _dbus_list_get_next_link (functions, link); - if (link == NULL) - { - fprintf (stderr, "Ran out of functions loading .da file\n"); - goto done; - } - current_func = link->data; - current_block = 0; - } - - current_arc = current_func->block_graph[current_block].succ; - } - else - { - current_arc = current_arc->succ_next; - } - } - - _dbus_assert (current_arc != NULL); - _dbus_assert (!current_arc->on_tree); - - current_arc->arc_count = val; - current_arc->count_valid = TRUE; - current_func->block_graph[current_block].succ_count -= 1; - current_func->block_graph[current_arc->target].pred_count -= 1; - - ++n_arcs; - - current_arc = current_arc->succ_next; - } - - done: - - if (n_arcs != claimed_n_arcs) - { - fprintf (stderr, "File claimed to have %d arcs but only had %d\n", - claimed_n_arcs, n_arcs); - exit (1); - } - -#if 0 - printf ("%d arcs in file\n", n_arcs); -#endif -} -#endif - -static void -function_solve_graph (Function *func) -{ - int passes, changes; - dbus_int64_t total; - int i; - Arc *arc; - Block *block_graph; - int n_blocks; - -#if 0 - printf ("Solving function graph\n"); -#endif - - n_blocks = func->n_blocks; - block_graph = func->block_graph; - - /* For every block in the file, - - if every exit/entrance arc has a known count, then set the block count - - if the block count is known, and every exit/entrance arc but one has - a known execution count, then set the count of the remaining arc - - As arc counts are set, decrement the succ/pred count, but don't delete - the arc, that way we can easily tell when all arcs are known, or only - one arc is unknown. */ - - /* The order that the basic blocks are iterated through is important. - Since the code that finds spanning trees starts with block 0, low numbered - arcs are put on the spanning tree in preference to high numbered arcs. - Hence, most instrumented arcs are at the end. Graph solving works much - faster if we propagate numbers from the end to the start. - - This takes an average of slightly more than 3 passes. */ - - changes = 1; - passes = 0; - while (changes) - { - passes++; - changes = 0; - - for (i = n_blocks - 1; i >= 0; i--) - { - if (! block_graph[i].count_valid) - { - if (block_graph[i].succ_count == 0) - { - total = 0; - for (arc = block_graph[i].succ; arc; - arc = arc->succ_next) - total += arc->arc_count; - block_graph[i].exec_count = total; - block_graph[i].count_valid = 1; - changes = 1; - } - else if (block_graph[i].pred_count == 0) - { - total = 0; - for (arc = block_graph[i].pred; arc; - arc = arc->pred_next) - total += arc->arc_count; - block_graph[i].exec_count = total; - block_graph[i].count_valid = 1; - changes = 1; - } - } - if (block_graph[i].count_valid) - { - if (block_graph[i].succ_count == 1) - { - total = 0; - /* One of the counts will be invalid, but it is zero, - so adding it in also doesn't hurt. */ - for (arc = block_graph[i].succ; arc; - arc = arc->succ_next) - total += arc->arc_count; - /* Calculate count for remaining arc by conservation. */ - total = block_graph[i].exec_count - total; - /* Search for the invalid arc, and set its count. */ - for (arc = block_graph[i].succ; arc; - arc = arc->succ_next) - if (! arc->count_valid) - break; - if (! arc) - die ("arc == NULL\n"); - arc->count_valid = 1; - arc->arc_count = total; - block_graph[i].succ_count -= 1; - - block_graph[arc->target].pred_count -= 1; - changes = 1; - } - if (block_graph[i].pred_count == 1) - { - total = 0; - /* One of the counts will be invalid, but it is zero, - so adding it in also doesn't hurt. */ - for (arc = block_graph[i].pred; arc; - arc = arc->pred_next) - total += arc->arc_count; - /* Calculate count for remaining arc by conservation. */ - total = block_graph[i].exec_count - total; - /* Search for the invalid arc, and set its count. */ - for (arc = block_graph[i].pred; arc; - arc = arc->pred_next) - if (! arc->count_valid) - break; - if (! arc) - die ("arc == NULL\n"); - arc->count_valid = 1; - arc->arc_count = total; - block_graph[i].pred_count -= 1; - - block_graph[arc->source].succ_count -= 1; - changes = 1; - } - } - } - } - - /* If the graph has been correctly solved, every block will have a - * succ and pred count of zero. - */ - { - dbus_bool_t header = FALSE; - for (i = 0; i < n_blocks; i++) - { - if (block_graph[i].succ_count || block_graph[i].pred_count) - { - if (!header) - { - fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n", - func->name); - fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n"); - header = TRUE; - } - fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n", - i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count); - } - } - } -} - -static void -solve_graphs (DBusList **functions) -{ - DBusList *link; - - link = _dbus_list_get_first_link (functions); - while (link != NULL) - { - Function *func = link->data; - - function_solve_graph (func); - - link = _dbus_list_get_next_link (functions, link); - } -} - -static void -load_functions_for_c_file (const DBusString *filename, - DBusList **functions) -{ - DBusString bbg_filename; - DBusString da_filename; - DBusString gcno_filename; - DBusString gcda_filename; - DBusString contents; - DBusString *name; - DBusError error; - - /* With latest gcc it's .gcno instead of .bbg and - * gcda instead of .da - */ - - dbus_error_init (&error); - - if (!_dbus_string_init (&bbg_filename) || - !_dbus_string_init (&da_filename) || - !_dbus_string_init (&gcno_filename) || - !_dbus_string_init (&gcda_filename) || - !_dbus_string_copy (filename, 0, &bbg_filename, 0) || - !_dbus_string_copy (filename, 0, &da_filename, 0) || - !_dbus_string_copy (filename, 0, &gcno_filename, 0) || - !_dbus_string_copy (filename, 0, &gcda_filename, 0) || - !_dbus_string_init (&contents)) - die ("no memory\n"); - - _dbus_string_shorten (&bbg_filename, 2); - _dbus_string_shorten (&da_filename, 2); - - if (!_dbus_string_append (&bbg_filename, ".bbg") || - !_dbus_string_append (&da_filename, ".da") || - !_dbus_string_append (&bbg_filename, ".gcno") || - !_dbus_string_append (&bbg_filename, ".gcda")) - die ("no memory\n"); - - if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename))) - name = &gcno_filename; - else - name = &bbg_filename; - - if (!_dbus_file_get_contents (&contents, name, - &error)) - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - exit (1); - } - - get_functions_from_bbg (&contents, functions); - - _dbus_string_set_length (&contents, 0); - - if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename))) - name = &gcda_filename; - else - name = &da_filename; - - if (!_dbus_file_get_contents (&contents, name, - &error)) - { - /* Try .libs/file.da */ - int slash; - - if (_dbus_string_find_byte_backward (name, - _dbus_string_get_length (name), - '/', - &slash)) - { - DBusString libs; - _dbus_string_init_const (&libs, "/.libs"); - - if (!_dbus_string_copy (&libs, 0, name, slash)) - die ("no memory"); - - dbus_error_free (&error); - if (!_dbus_file_get_contents (&contents, name, - &error)) - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - exit (1); - } - } - else - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - exit (1); - } - } - - add_counts_from_da (&contents, functions); - - solve_graphs (functions); - - _dbus_string_free (&contents); - _dbus_string_free (&da_filename); - _dbus_string_free (&bbg_filename); -} - -static void -get_lines_from_bb_file (const DBusString *contents, - File *fl) -{ - int i; - long val; - int n_functions; - dbus_bool_t in_our_file; - DBusList *link; - Function *func; - int block; - -#if 0 - printf ("Getting line numbers for blocks from .bb file\n"); -#endif - - /* There's this "filename" field in the .bb file which - * mysteriously comes *after* the first function in the - * file in the .bb file; and every .bb file seems to - * have only one filename. I don't understand - * what's going on here, so just set in_our_file = TRUE - * at the start categorically. - */ - - block = 0; - func = NULL; - in_our_file = TRUE; - link = _dbus_list_get_first_link (&fl->functions); - n_functions = 0; - i = 0; - while (string_get_int (contents, i, &val)) - { - i += 4; - - switch (val) - { - case BB_FILENAME: - { - DBusString f; - - if (!_dbus_string_init (&f)) - die ("no memory\n"); - - if (string_get_string (contents, i, - BB_FILENAME, - &f, &i)) - { - /* fl->name is a full path and the filename in .bb is - * not. - */ - DBusString tmp_str; - - _dbus_string_init_const (&tmp_str, fl->name); - - if (_dbus_string_ends_with_c_str (&tmp_str, - _dbus_string_get_const_data (&f))) - in_our_file = TRUE; - else - in_our_file = FALSE; - -#if 0 - fprintf (stderr, - "File %s in .bb, looking for %s, in_our_file = %d\n", - _dbus_string_get_const_data (&f), - fl->name, - in_our_file); -#endif - } - _dbus_string_free (&f); - } - break; - case BB_FUNCTION: - { - DBusString f; - if (!_dbus_string_init (&f)) - die ("no memory\n"); - - if (string_get_string (contents, i, - BB_FUNCTION, - &f, &i)) - { -#if 0 - fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f)); -#endif - - block = 0; - - if (in_our_file) - { - if (link == NULL) - { - fprintf (stderr, "No function object for function %s\n", - _dbus_string_get_const_data (&f)); - } - else - { - func = link->data; - link = _dbus_list_get_next_link (&fl->functions, link); - - if (func->name == NULL) - { - if (!_dbus_string_copy_data (&f, &func->name)) - die ("no memory\n"); - } - else - { - if (!_dbus_string_equal_c_str (&f, func->name)) - { - fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n", - func->name, strlen (func->name), - _dbus_string_get_const_data (&f), - _dbus_string_get_length (&f)); - - } - } - } - } - } - _dbus_string_free (&f); - - n_functions += 1; - } - break; - case BB_ENDOFLIST: - block += 1; - break; - default: -#if 0 - fprintf (stderr, "Line %ld\n", val); -#endif - - if (val >= fl->n_lines) - { - fprintf (stderr, "Line %ld but file only has %d lines\n", - val, fl->n_lines); - } - else if (func != NULL) - { - val -= 1; /* To convert the 1-based line number to 0-based */ - _dbus_assert (val >= 0); - - if (block < func->n_blocks) - { - if (!_dbus_list_append (&func->block_graph[block].lines, - &fl->lines[val])) - die ("no memory\n"); - - - if (!_dbus_list_append (&fl->lines[val].blocks, - &func->block_graph[block])) - die ("no memory\n"); - } - else - { - fprintf (stderr, "Line number for block %d but function only has %d blocks\n", - block, func->n_blocks); - } - } - else - { - fprintf (stderr, "Line %ld given outside of any function\n", - val); - } - - break; - } - } - -#if 0 - printf ("%d functions in file\n", n_functions); -#endif -} - - -static void -load_block_line_associations (const DBusString *filename, - File *f) -{ - DBusString bb_filename; - DBusString contents; - DBusError error; - - dbus_error_init (&error); - - if (!_dbus_string_init (&bb_filename) || - !_dbus_string_copy (filename, 0, &bb_filename, 0) || - !_dbus_string_init (&contents)) - die ("no memory\n"); - - _dbus_string_shorten (&bb_filename, 2); - - if (!_dbus_string_append (&bb_filename, ".bb")) - die ("no memory\n"); - - if (!_dbus_file_get_contents (&contents, &bb_filename, - &error)) - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - exit (1); - } - - get_lines_from_bb_file (&contents, f); - - _dbus_string_free (&contents); - _dbus_string_free (&bb_filename); -} - -static int -count_lines_in_string (const DBusString *str) -{ - int n_lines; - const char *p; - const char *prev; - const char *end; - const char *last_line_end; - -#if 0 - printf ("Counting lines in source file\n"); -#endif - - n_lines = 0; - prev = NULL; - p = _dbus_string_get_const_data (str); - end = p + _dbus_string_get_length (str); - last_line_end = p; - while (p != end) - { - /* too lazy to handle \r\n as one linebreak */ - if (*p == '\n' || *p == '\r') - { - ++n_lines; - last_line_end = p + 1; - } - - prev = p; - ++p; - } - - if (last_line_end != p) - ++n_lines; - - return n_lines; -} - -static void -fill_line_content (const DBusString *str, - Line *lines) -{ - int n_lines; - const char *p; - const char *prev; - const char *end; - const char *last_line_end; - -#if 0 - printf ("Saving contents of each line in source file\n"); -#endif - - n_lines = 0; - prev = NULL; - p = _dbus_string_get_const_data (str); - end = p + _dbus_string_get_length (str); - last_line_end = p; - while (p != end) - { - if (*p == '\n' || *p == '\r') - { - lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1); - if (lines[n_lines].text == NULL) - die ("no memory\n"); - - memcpy (lines[n_lines].text, last_line_end, p - last_line_end); - lines[n_lines].number = n_lines + 1; - - ++n_lines; - - last_line_end = p + 1; - } - - prev = p; - ++p; - } - - if (p != last_line_end) - { - memcpy (lines[n_lines].text, last_line_end, p - last_line_end); - ++n_lines; - } -} - -static void -mark_inside_dbus_build_tests (File *f) -{ - int i; - DBusList *link; - int inside_depth; - - inside_depth = 0; - i = 0; - while (i < f->n_lines) - { - Line *l = &f->lines[i]; - dbus_bool_t is_verbose; - - is_verbose = strstr (l->text, "_dbus_verbose") != NULL; - - if (inside_depth == 0) - { - const char *a, *b; - - a = strstr (l->text, "#if"); - b = strstr (l->text, "DBUS_BUILD_TESTS"); - if (a && b && (a < b)) - inside_depth += 1; - } - else - { - if (strstr (l->text, "#if") != NULL) - inside_depth += 1; - else if (strstr (l->text, "#endif") != NULL) - inside_depth -= 1; - } - - if (inside_depth > 0 || is_verbose) - { - /* Mark the line and its blocks */ - DBusList *blink; - - l->inside_dbus_build_tests = TRUE; - - blink = _dbus_list_get_first_link (&l->blocks); - while (blink != NULL) - { - Block *b = blink->data; - - b->inside_dbus_build_tests = TRUE; - - blink = _dbus_list_get_next_link (&l->blocks, blink); - } - } - - ++i; - } - - /* Now mark functions where for all blocks that are associated - * with a source line, the block is inside_dbus_build_tests. - */ - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - /* The issue is that some blocks aren't associated with a source line. - * Assume they are inside/outside tests according to the source - * line of the preceding block. For the first block, make it - * match the first following block with a line associated. - */ - if (func->block_graph[0].lines == NULL) - { - /* find first following line */ - i = 1; - while (i < func->n_blocks) - { - if (func->block_graph[i].lines != NULL) - { - func->block_graph[0].inside_dbus_build_tests = - func->block_graph[i].inside_dbus_build_tests; - break; - } - - ++i; - } - } - - /* Now mark all blocks but the first */ - i = 1; - while (i < func->n_blocks) - { - if (func->block_graph[i].lines == NULL) - { - func->block_graph[i].inside_dbus_build_tests = - func->block_graph[i-1].inside_dbus_build_tests; - } - - ++i; - } - - i = 0; - while (i < func->n_blocks) - { - /* Break as soon as any block is not a test block */ - if (func->block_graph[i].lines != NULL && - !func->block_graph[i].inside_dbus_build_tests) - break; - - ++i; - } - - if (i == func->n_blocks) - func->inside_dbus_build_tests = TRUE; - - link = _dbus_list_get_next_link (&f->functions, link); - } -} - -static void -mark_coverage (File *f) -{ - int i; - DBusList *link; - - i = 0; - while (i < f->n_lines) - { - Line *l = &f->lines[i]; - DBusList *blink; - int n_blocks; - int n_blocks_executed; - - n_blocks = 0; - n_blocks_executed = 0; - blink = _dbus_list_get_first_link (&l->blocks); - while (blink != NULL) - { - Block *b = blink->data; - - if (b->exec_count > 0) - n_blocks_executed += 1; - - n_blocks += 1; - - blink = _dbus_list_get_next_link (&l->blocks, blink); - } - - if (n_blocks_executed > 0 && - n_blocks_executed < n_blocks) - l->partial = TRUE; - - ++i; - } - - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - int i; - int n_test_blocks; - int n_test_blocks_executed; - int n_nontest_blocks; - int n_nontest_blocks_executed; - - n_test_blocks = 0; - n_test_blocks_executed = 0; - n_nontest_blocks = 0; - n_nontest_blocks_executed = 0; - - i = 0; - while (i < func->n_blocks) - { - if (!func->block_graph[i].inside_dbus_build_tests) - { - n_nontest_blocks += 1; - - if (func->block_graph[i].exec_count > 0) - n_nontest_blocks_executed += 1; - } - else - { - n_test_blocks += 1; - - if (func->block_graph[i].exec_count > 0) - n_test_blocks_executed += 1; - } - - ++i; - } - - if (n_nontest_blocks_executed > 0 && - n_nontest_blocks_executed < n_nontest_blocks) - func->partial = TRUE; - - if (n_nontest_blocks_executed == 0 && - n_nontest_blocks > 0) - func->unused = TRUE; - - func->n_test_blocks = n_test_blocks; - func->n_test_blocks_executed = n_test_blocks_executed; - func->n_nontest_blocks = n_nontest_blocks; - func->n_nontest_blocks_executed = n_nontest_blocks_executed; - - link = _dbus_list_get_next_link (&f->functions, link); - } -} - -static File* -load_c_file (const DBusString *filename) -{ - DBusString contents; - DBusError error; - File *f; - - f = dbus_new0 (File, 1); - if (f == NULL) - die ("no memory\n"); - - if (!_dbus_string_copy_data (filename, &f->name)) - die ("no memory\n"); - - if (!_dbus_string_init (&contents)) - die ("no memory\n"); - - dbus_error_init (&error); - - if (!_dbus_file_get_contents (&contents, filename, - &error)) - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - dbus_error_free (&error); - exit (1); - } - - load_functions_for_c_file (filename, &f->functions); - - f->n_lines = count_lines_in_string (&contents); - f->lines = dbus_new0 (Line, f->n_lines); - if (f->lines == NULL) - die ("no memory\n"); - - fill_line_content (&contents, f->lines); - - _dbus_string_free (&contents); - - load_block_line_associations (filename, f); - - mark_inside_dbus_build_tests (f); - mark_coverage (f); - - return f; -} - -typedef struct Stats Stats; - -struct Stats -{ - int n_blocks; - int n_blocks_executed; - int n_blocks_inside_dbus_build_tests; - - int n_lines; /* lines that have blocks on them */ - int n_lines_executed; - int n_lines_partial; - int n_lines_inside_dbus_build_tests; - - int n_functions; - int n_functions_executed; - int n_functions_partial; - int n_functions_inside_dbus_build_tests; -}; - -static dbus_bool_t -line_was_executed (Line *l) -{ - DBusList *link; - - link = _dbus_list_get_first_link (&l->blocks); - while (link != NULL) - { - Block *b = link->data; - - if (b->exec_count > 0) - return TRUE; - - link = _dbus_list_get_next_link (&l->blocks, link); - } - - return FALSE; -} - - -static int -line_exec_count (Line *l) -{ - DBusList *link; - dbus_int64_t total; - - total = 0; - link = _dbus_list_get_first_link (&l->blocks); - while (link != NULL) - { - Block *b = link->data; - - total += b->exec_count; - - link = _dbus_list_get_next_link (&l->blocks, link); - } - - return total; -} - -static void -merge_stats_for_file (Stats *stats, - File *f) -{ - int i; - DBusList *link; - - for (i = 0; i < f->n_lines; ++i) - { - Line *l = &f->lines[i]; - - if (l->inside_dbus_build_tests) - { - stats->n_lines_inside_dbus_build_tests += 1; - continue; - } - - if (line_was_executed (l)) - stats->n_lines_executed += 1; - - if (l->blocks != NULL) - stats->n_lines += 1; - - if (l->partial) - stats->n_lines_partial += 1; - } - - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - if (func->inside_dbus_build_tests) - stats->n_functions_inside_dbus_build_tests += 1; - else - { - stats->n_functions += 1; - - if (!func->unused) - stats->n_functions_executed += 1; - - if (func->partial) - stats->n_functions_partial += 1; - } - - stats->n_blocks_inside_dbus_build_tests += - func->n_test_blocks; - - stats->n_blocks_executed += - func->n_nontest_blocks_executed; - - stats->n_blocks += - func->n_nontest_blocks; - - link = _dbus_list_get_next_link (&f->functions, link); - } -} - -/* The output of this matches gcov exactly ("diff" shows no difference) */ -static void -print_annotated_source_gcov_format (File *f) -{ - int i; - - i = 0; - while (i < f->n_lines) - { - Line *l = &f->lines[i]; - - if (l->blocks != NULL) - { - int exec_count; - - exec_count = line_exec_count (l); - - if (exec_count > 0) - printf ("%12d %s\n", - exec_count, l->text); - else - printf (" ###### %s\n", l->text); - } - else - { - printf ("\t\t%s\n", l->text); - } - - ++i; - } -} - -static void -print_annotated_source (File *f) -{ - int i; - - i = 0; - while (i < f->n_lines) - { - Line *l = &f->lines[i]; - - if (l->inside_dbus_build_tests) - printf ("*"); - else - printf (" "); - - if (l->blocks != NULL) - { - int exec_count; - - exec_count = line_exec_count (l); - - if (exec_count > 0) - printf ("%12d %s\n", - exec_count, l->text); - else - printf (" ###### %s\n", l->text); - } - else - { - printf ("\t\t%s\n", l->text); - } - - ++i; - } -} - -static void -print_block_superdetails (File *f) -{ - DBusList *link; - int i; - - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - printf ("=== %s():\n", func->name); - - i = 0; - while (i < func->n_blocks) - { - Block *b = &func->block_graph[i]; - DBusList *l; - - printf (" %5d executed %d times%s\n", i, - (int) b->exec_count, - b->inside_dbus_build_tests ? - " [inside DBUS_BUILD_TESTS]" : ""); - - l = _dbus_list_get_first_link (&b->lines); - while (l != NULL) - { - Line *line = l->data; - - printf ("4%d\t%s\n", line->number, line->text); - - l = _dbus_list_get_next_link (&b->lines, l); - } - - ++i; - } - - link = _dbus_list_get_next_link (&f->functions, link); - } -} - -static void -print_one_file (const DBusString *filename) -{ - if (_dbus_string_ends_with_c_str (filename, ".bb")) - { - DBusString contents; - DBusError error; - - if (!_dbus_string_init (&contents)) - die ("no memory\n"); - - dbus_error_init (&error); - - if (!_dbus_file_get_contents (&contents, filename, - &error)) - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - dbus_error_free (&error); - exit (1); - } - - dump_bb_file (&contents); - - _dbus_string_free (&contents); - } - else if (_dbus_string_ends_with_c_str (filename, ".bbg")) - { - DBusString contents; - DBusError error; - - if (!_dbus_string_init (&contents)) - die ("no memory\n"); - - dbus_error_init (&error); - - if (!_dbus_file_get_contents (&contents, filename, - &error)) - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - dbus_error_free (&error); - exit (1); - } - - dump_bbg_file (&contents); - - _dbus_string_free (&contents); - } - else if (_dbus_string_ends_with_c_str (filename, ".da")) - { - DBusString contents; - DBusError error; - - if (!_dbus_string_init (&contents)) - die ("no memory\n"); - - dbus_error_init (&error); - - if (!_dbus_file_get_contents (&contents, filename, - &error)) - { - fprintf (stderr, "Could not open file: %s\n", - error.message); - dbus_error_free (&error); - exit (1); - } - - dump_da_file (&contents); - - _dbus_string_free (&contents); - } - else if (_dbus_string_ends_with_c_str (filename, ".c")) - { - File *f; - - f = load_c_file (filename); - - print_annotated_source (f); - } - else - { - fprintf (stderr, "Unknown file type %s\n", - _dbus_string_get_const_data (filename)); - exit (1); - } -} - -static void -print_untested_functions (File *f) -{ - DBusList *link; - dbus_bool_t found; - - found = FALSE; - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - if (func->unused && - !func->inside_dbus_build_tests) - found = TRUE; - - link = _dbus_list_get_next_link (&f->functions, link); - } - - if (!found) - return; - - printf ("Untested functions in %s\n", f->name); - printf ("=======\n"); - - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - if (func->unused && - !func->inside_dbus_build_tests) - printf (" %s\n", func->name); - - link = _dbus_list_get_next_link (&f->functions, link); - } - - printf ("\n"); -} - -static void -print_poorly_tested_functions (File *f, - Stats *stats) -{ - DBusList *link; - dbus_bool_t found; - -#define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks) - -#define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks) - -#define POORLY_TESTED(function) (!(function)->unused && \ - (function)->n_nontest_blocks > 0 && \ - TEST_FRACTION (function) < AVERAGE_COVERAGE) - - found = FALSE; - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - if (POORLY_TESTED (func)) - found = TRUE; - - link = _dbus_list_get_next_link (&f->functions, link); - } - - if (!found) - return; - - printf ("Below average functions in %s\n", f->name); - printf ("=======\n"); - - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - if (POORLY_TESTED (func)) - printf (" %s (%d%%)\n", func->name, - (int) (TEST_FRACTION (func) * 100)); - - link = _dbus_list_get_next_link (&f->functions, link); - } - - printf ("\n"); -} - -static int -func_cmp (const void *a, - const void *b) -{ - Function *af = *(Function**) a; - Function *bf = *(Function**) b; - int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed; - int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed; - - /* Sort by number of untested blocks */ - return b_untested - a_untested; -} - -static void -print_n_untested_blocks_by_function (File *f, - Stats *stats) -{ - DBusList *link; - Function **funcs; - int n_found; - int i; - - n_found = 0; - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - if (func->n_nontest_blocks_executed < - func->n_nontest_blocks) - n_found += 1; - - link = _dbus_list_get_next_link (&f->functions, link); - } - - if (n_found == 0) - return; - - /* make an array so we can use qsort */ - - funcs = dbus_new (Function*, n_found); - if (funcs == NULL) - return; - - i = 0; - link = _dbus_list_get_first_link (&f->functions); - while (link != NULL) - { - Function *func = link->data; - - if (func->n_nontest_blocks_executed < - func->n_nontest_blocks) - { - funcs[i] = func; - ++i; - } - - link = _dbus_list_get_next_link (&f->functions, link); - } - - _dbus_assert (i == n_found); - - qsort (funcs, n_found, sizeof (Function*), - func_cmp); - - printf ("Incomplete functions in %s\n", f->name); - printf ("=======\n"); - - i = 0; - while (i < n_found) - { - Function *func = funcs[i]; - - printf (" %s (%d/%d untested blocks)\n", - func->name, - func->n_nontest_blocks - func->n_nontest_blocks_executed, - func->n_nontest_blocks); - - ++i; - } - - dbus_free (funcs); - - printf ("\n"); -} - -static void -print_stats (Stats *stats, - const char *of_what) -{ - int completely; - - printf ("Summary (%s)\n", of_what); - printf ("=======\n"); - printf (" %g%% blocks executed (%d of %d)\n", - (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0, - stats->n_blocks_executed, - stats->n_blocks); - - printf (" (ignored %d blocks of test-only/debug-only code)\n", - stats->n_blocks_inside_dbus_build_tests); - - printf (" %g%% functions executed (%d of %d)\n", - (stats->n_functions_executed / (double) stats->n_functions) * 100.0, - stats->n_functions_executed, - stats->n_functions); - - completely = stats->n_functions_executed - stats->n_functions_partial; - printf (" %g%% functions completely executed (%d of %d)\n", - (completely / (double) stats->n_functions) * 100.0, - completely, - stats->n_functions); - - printf (" (ignored %d functions of test-only/debug-only code)\n", - stats->n_functions_inside_dbus_build_tests); - - printf (" %g%% lines executed (%d of %d)\n", - (stats->n_lines_executed / (double) stats->n_lines) * 100.0, - stats->n_lines_executed, - stats->n_lines); - - completely = stats->n_lines_executed - stats->n_lines_partial; - printf (" %g%% lines completely executed (%d of %d)\n", - (completely / (double) stats->n_lines) * 100.0, - completely, - stats->n_lines); - - printf (" (ignored %d lines of test-only/debug-only code)\n", - stats->n_lines_inside_dbus_build_tests); - - printf ("\n"); -} - -typedef enum -{ - MODE_PRINT, - MODE_REPORT, - MODE_BLOCKS, - MODE_GCOV -} Mode; - -int -main (int argc, char **argv) -{ - DBusString filename; - int i; - Mode m; - - if (argc < 2) - { - fprintf (stderr, "Must specify files on command line\n"); - return 1; - } - - m = MODE_PRINT; - i = 1; - - if (strcmp (argv[i], "--report") == 0) - { - m = MODE_REPORT; - ++i; - } - else if (strcmp (argv[i], "--blocks") == 0) - { - m = MODE_BLOCKS; - ++i; - } - else if (strcmp (argv[i], "--gcov") == 0) - { - m = MODE_GCOV; - ++i; - } - - - if (i == argc) - { - fprintf (stderr, "Must specify files on command line\n"); - return 1; - } - - if (m == MODE_PRINT) - { - while (i < argc) - { - _dbus_string_init_const (&filename, argv[i]); - - print_one_file (&filename); - - ++i; - } - } - else if (m == MODE_BLOCKS || m == MODE_GCOV) - { - while (i < argc) - { - File *f; - - _dbus_string_init_const (&filename, argv[i]); - - f = load_c_file (&filename); - - if (m == MODE_BLOCKS) - print_block_superdetails (f); - else if (m == MODE_GCOV) - print_annotated_source_gcov_format (f); - - ++i; - } - } - else if (m == MODE_REPORT) - { - Stats stats = { 0, }; - DBusList *files; - DBusList *link; - DBusHashTable *stats_by_dir; - DBusHashIter iter; - - files = NULL; - while (i < argc) - { - _dbus_string_init_const (&filename, argv[i]); - - if (_dbus_string_ends_with_c_str (&filename, ".c")) - { - File *f; - - f = load_c_file (&filename); - - if (!_dbus_list_append (&files, f)) - die ("no memory\n"); - } - else - { - fprintf (stderr, "Unknown file type %s\n", - _dbus_string_get_const_data (&filename)); - exit (1); - } - - ++i; - } - - link = _dbus_list_get_first_link (&files); - while (link != NULL) - { - File *f = link->data; - - merge_stats_for_file (&stats, f); - - link = _dbus_list_get_next_link (&files, link); - } - - print_stats (&stats, "all files"); - - stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING, - dbus_free, dbus_free); - - link = _dbus_list_get_first_link (&files); - while (link != NULL) - { - File *f = link->data; - DBusString dirname; - char *dirname_c; - Stats *dir_stats; - - _dbus_string_init_const (&filename, f->name); - - if (!_dbus_string_init (&dirname)) - die ("no memory\n"); - - if (!_dbus_string_get_dirname (&filename, &dirname) || - !_dbus_string_copy_data (&dirname, &dirname_c)) - die ("no memory\n"); - - dir_stats = _dbus_hash_table_lookup_string (stats_by_dir, - dirname_c); - - if (dir_stats == NULL) - { - dir_stats = dbus_new0 (Stats, 1); - if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c, - dir_stats)) - die ("no memory\n"); - } - else - dbus_free (dirname_c); - - merge_stats_for_file (dir_stats, f); - - link = _dbus_list_get_next_link (&files, link); - } - - _dbus_hash_iter_init (stats_by_dir, &iter); - while (_dbus_hash_iter_next (&iter)) - { - const char *dirname = _dbus_hash_iter_get_string_key (&iter); - Stats *dir_stats = _dbus_hash_iter_get_value (&iter); - - print_stats (dir_stats, dirname); - } - - _dbus_hash_table_unref (stats_by_dir); - - link = _dbus_list_get_first_link (&files); - while (link != NULL) - { - File *f = link->data; - - print_untested_functions (f); - - link = _dbus_list_get_next_link (&files, link); - } - - link = _dbus_list_get_first_link (&files); - while (link != NULL) - { - File *f = link->data; - - print_poorly_tested_functions (f, &stats); - - link = _dbus_list_get_next_link (&files, link); - } - - link = _dbus_list_get_first_link (&files); - while (link != NULL) - { - File *f = link->data; - - print_n_untested_blocks_by_function (f, &stats); - - link = _dbus_list_get_next_link (&files, link); - } - } - - return 0; -} diff --git a/tools/lcov.am b/tools/lcov.am new file mode 100644 index 0000000..3178ba9 --- /dev/null +++ b/tools/lcov.am @@ -0,0 +1,46 @@ +# Copyright © 2008-2011 Collabora Ltd. +# Copyright © 2008-2011 Nokia Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +lcov-reset: + lcov --directory @abs_top_srcdir@ --zerocounters + +# gcov takes ~forever to process config-parser.c for some reason? +lcov-report: + true > bus/bus_test-config-parser.gcno + true > bus/dbus_daemon-config-parser.gcno + lcov --directory @abs_top_srcdir@ --capture \ + --output-file @abs_top_builddir@/lcov.info + $(mkdir_p) @abs_top_builddir@/lcov.html + git_commit=`GIT_DIR=@abs_top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\ + genhtml --title "@PACKAGE_STRING@ $$git_commit" \ + --output-directory @abs_top_builddir@/lcov.html lcov.info + @echo + @echo 'lcov report can be found in:' + @echo 'file://@abs_top_builddir@/lcov.html/index.html' + @echo + +lcov-check: + $(MAKE) lcov-reset + $(MAKE) check $(LCOV_CHECK_ARGS) + $(MAKE) lcov-report + +## vim:set ft=automake: -- 1.7.2.3