Search code examples
cgccautotoolslibtoolgcov

Libtool prefixes objects but gcov requires them without prefix


I need to perform some test coverage with gcov on a shared library I am working on.

The problem is libtool renames the object files from my-name.c to libmylib_la-my-name.lo and gcov is unable to handle that conversion. Everytime I run it, the error cannot open notes file is generated.

If I manually rename my-name.c to libmylib_la-my-name.c after the build gcov works fine, so there is no other problem apart the filename mangling.

Addendum

Trying to provide a minimal working example I discovered the filename mangling happens only when lib..._la_CFLAGS is set (and also when it is set to an empty value).

cat <<EOT > configure.ac
AC_INIT(sample,0.0.1)
AC_CONFIG_SRCDIR(configure.ac)
AM_INIT_AUTOMAKE(foreign)
LT_INIT
AC_PROG_CC
AC_CONFIG_FILES(Makefile)
AC_OUTPUT
EOT

cat <<EOT > Makefile.am
lib_LTLIBRARIES=libsample.la
libsample_la_SOURCES=sample.c
# The following line triggers the filename mangling (libsample_la-sample.lo instead of sample.lo)
libsample_la_CFLAGS=
EOT

touch sample.c && autoreconf -if && ./configure && make

Is there a way to avoid the filename mangling operated by libtool or to let gcov understand the filename mangling scheme?


Solution

  • Gcov gcda and gcno files are named after object files. You can run gcov from source directory directly on object file or you can use -o option of gcov to specify the object file and corresponding gcov files.

    For example I have a small project that builds a shared library. I pass gcov flags to make command:

    make CFLAGS="-O0 --coverage" LDFLAGS=--coverage
    

    Object files and corresponding gcno files are created in src/.libs folder:

    $ ls -la src/.libs
    libtest_la-test.o
    libtest_la-test.gcno
    

    The source file is in src folder

    $ ls src/
    test.c
    

    Next I run my test suite and gcda files are created:

    $ ls -la src/.libs
    libtest_la-test.o
    libtest_la-test.gcno
    libtest_la-test.gcda
    

    Now I can enter src directory and run gcov, specifiying object file name:

    $ gcov -o .libs/libtest_la-test.o test.c
    File ‘test.c’
    Lines executed:27.08% of 96
    Creating ‘test.c.gcov'
    

    It is also possible to just run gcov on object file:

    $ gcov .libs/libtest_la-test.o
    File ’test.c’
    Lines executed:27.08% of 96
    Creating ’test.c.gcov'
    

    Or even just specifying base name of object file and gcov files:

    $ gcov .libs/libtest_la-test
    File ’test.c’
    Lines executed:27.08% of 96
    Creating ’test.c.gcov'
    

    But I would suggest another automated approach that works very well for me, using lcov. I invoke it from top directory specifying paths to source files and object files:

    $ lcov --base-directory src --directory src/.libs/ --capture --output-file gcov.info
    Capturing coverage data from src/.libs/
    Found gcov version: 4.8.2
    Scanning src/.libs/ for .gcda files ...
    Found 10 data files in src/.libs/
    Processing .libs/test_la-test.gcda
    […]
    Finished .info-file creation
    
    $ genhtml -o html/coverage gcov.info
    Reading data file gcov.info
    Found 10 entries.
    Found common filename prefix "/usr/src/libtest”
    Writing .css and .png files.
    Generating output.
    Processing file src/test.c
    […]
    Writing directory view page.
    Overall coverage rate:
      lines......: 56.1% (2098 of 3737 lines)
      functions..: 68.8% (139 of 202 functions)
    

    Now html/coverage directory contains html files that can be easily analyzed in a web browser.

    lcov screenshot