Tag Archives: gcov

Non-recursive automake

A while back, I was toying with the idea of adding gcov support to libgdata, to give metrics on the code coverage of the test suite. I played around with adding it, but my attempts were thwarted by the fact that I couldn't easily get a list of all C files which were to be compiled, in all source directories, to use in the top-level Makefile.

I recently found a little time to work on this some more and, as usually happens, it ballooned into something bigger, and I ended up redoing the entire build system for libgdata. It now uses non-recursive automake, which makes things a lot simpler in many respects. The diffstat was favourable ("21 files changed, 641 insertions(+), 833 deletions(-)"), and it has made the autogen/clean/build cycle about 20 seconds faster (on average, from some very rough tests). Accomplishing this was largely possible due to the (fairly) recent literature on the subject from Murray Cumming and Daniel Elstner, which proved rather useful; so many thanks to them.

As a result of all this, I now know that only just over 50% of libgdata's code was actually being exercised before by the test suite. I've now pushed this up to 60%, and uncovered a few buglets in the process. I dread to think what other problems lie in the remaining 40%; there's certainly lots of work left to be done.

Anyway, since all the snippets of automake magic I could find were subtly incompatible with non-recursive automake, I ended up with a slightly different one (based on gobject-introspection's gcov support). Hopefully it's useful to someone, though it could probably do with some tidying up:

if GCOV_ENABLED
gcov-report.txt: gcov-clean all check
	$(AM_V_GEN)(rm -f $@; \
	echo -e "Test coverage for libgdata:\n" >> $@; \
	total_covered=0; total_actual=0; \
	for file in $(filter %.c,$(gdata_libgdata_la_SOURCES)); do \
	  file2=\(\){file%/*}; \
	  gcov -o `find -newer \(\){file2/.c/.gcda}" -print0 | sed -e 's/\.gcda/\.o/'` \(\)file2.gcov; then \
	    actual=`grep -v '        -:' \(\)file2.gcov | wc -l`; \
	    covered=\(\)((total_covered + covered)); \
	    total_actual=\(\)file:\t\(\)actual\t(\(\)covered * 100) / \(\)total_actual\nCovered statements: \(\)(((\(\)total_actual))%" >> $@)

gcov: gcov-report.txt
	@cat gcov-report.txt

clean: gcov-clean
gcov-clean:
	@find . -name "*.gcda" -o -name "*.gcov" -delete

MAINTAINERCLEANFILES += gcov-report.txt

.PHONY: gcov gcov-clean gcov-report.txt
else
gcov:
	@echo "Need to reconfigure with --enable-gcov"
endif

It will output a code coverage report of the test suite (`make check`) when `make gcov` is called, and will also save it as "gcov-report.txt" in the root source directory.