3

I'm trying to use gcovr 4.1 to generate coverage reports for a shared library project in C++/Qt while running unit tests. I had no problems instrumenting my code but am having trouble getting gcda files for the library and also having trouble getting a complete report for even the unit tests which did yield gcda files.

My project has the following hierarchy after running make in project-root and executing the unit tests by calling x64/release/tests:

project-root/
├─ Makefile
├─ build
|  ├─ library/
|  |  ├─ GeneratedFiles/
|  |  |  └─ <cpp files generated by Qt's moc compiler>
|  |  └─ obj
|  |     └─ <*.o, *.gcno, *.gcda> (gcda files show up after Edit #2)
|  └─ tests/
|     ├─ GeneratedFiles/
|     |  └─ <cpp files generated by Qt's moc compiler>
|     └─ obj
|        └─ <*.o, *.gcno, *.gcda>
├─ library/
|  ├─ Makefile
|  └─ src/
|     ├─ subdir/
|     |  └─ <source files>
|     └─ <other source files>
├─ tests/
|  ├─ Makefile
|  └─ src/
|     ├─ subdir/
|     |  └─ <source files>
|     └─ <other source files>  
└─ x64/  
   └─ release/
      ├─ tests
      └─ library.so

Note that build/library/obj does not contain any gcda files while build/tests/obj does. Altogether, 11 gcda files exist in the latter directory.

I have tried running gcovr from several directories with various filters. Some examples that at least produced some output:

[user@50f886c6bdeb project-root] gcovr

Attempting to specify source directories:

[user@50f886c6bdeb project-root] gcovr --filter library/src/ --filter tests/src/

Specifying the root with full paths:

[user@50f886c6bdeb project-root] gcovr -r /code/project-root/ --filter /code/project-root/library/src/ --filter /code/project-root/tests/src/

Each of these (along with several other variations) produce identical results.

  • I get a long list of "Cannot open source file" messages
  • It reports coverage for the files immediately in tests/src but not for those in tests/src/subdir even though I can verify that the gcda files in the subdirectory contain data by examining them with gcov.

The cpp files in build/.../GeneratedFiles are getting instrumented (i.e. have corresponding gcno files); however, I don't really care much whether or not their data is included in the report. I do need to figure out:

  1. How do I get the gcda files to generate for the library while executing the unit tests?
  2. What command line do I use to allow gcovr to pair up the results and source for this structure?

I appreciate any help!

Edit #1: Added locations of Makefiles and clarified on building/running the binary.

Edit #2:
Part of the mystery solved. A typo in my Qt *.pro file prevented -fprofile-arcs from being included in the linker flags for the library.
I found help through this question: gcov: producing .gcda output from shared library?
which led me to this gcc help thread: gcov support for shared library
which eventually got me to check where the compiler was trying to save gcda files by running:

[user@50f886c6bdeb release]strings library.so | grep gcda

There were no entries, so I double checked the build settings for the library and found my mistake. With that fixed, gcda files are produced for the library files, and gcov can create a report with them - including the files in library/src/subdir (contradictory to the behavior for the tests binary).
However, I still see all of the same "Cannot open source file" messages. Attempting to build a detailed HTML report fails with an error as a result.

Tiberius
  • 31
  • 4
  • This question is really well written, thank you! (1) The lack of gcda files indicates that the corresponding object files were never executed. Is the library linked with your tests (how?), or is the source of the library independently included into the tests? – amon Apr 11 '19 at 10:17
  • (2) Gcovr tries various heuristics to guess where the compiler was run which is necessary to resolve the paths to the source files. Ideally, gcovr is invoked from the same directory as the compiler. (a) This is often the build directory, then also adjust the `--root` directory to point to the project. (b) You can try `--object-directory` to switch to a different set of heuristics. It could be that the use of Qt is interfering with proper file name resolution. Are the error messages talking about generated file names or the source file names, or both? – amon Apr 11 '19 at 10:18
  • @amon Thanks for the replies. To answer your questions: (1) The library is compiled as a shared library which is loaded at run time by the test driver program. The file `x64/release/tests` is a small binary that includes classes of the form `TestLibraryClassX` while `x64/release/library.so` is the shared library which contains `LibraryClassX`. To build these, I run make using a toplevel Makefile in `project-root` which ultimately cd's into `library` and `tests` to call make using the Makefiles in each of those directories. – Tiberius Apr 11 '19 at 15:26
  • @amon (2) When I invoke gcovr from project-root (where I call make directly), I do get coverage information for the files specifically in `tests/src`. I get "Cannot open source file" errors for every file name, both generated and source, everywhere else - including those in `tests/src/subdir`. (a) Not sure if this is what you meant, but I tried running from within the subdirectories since make was called in each of them. The calls took the form: `[user@50f886c6bdeb tests] gcovr --root /code/project-root/` Both calls yielded the same result as calling from project-root. – Tiberius Apr 11 '19 at 15:46
  • (b) I'm not sure which obj directory would be the correct choice in this situation. It seems that gcovr correctly finds all of the gcno files in both obj directories; however, it is having trouble mapping back to the correct source directories. I can try this if you want though. – Tiberius Apr 11 '19 at 15:52
  • The problem is that the gcno files contain a relative path to the source files, but the path is relative to the directory where the compiler (gcc) was invoked. If you have a recursive Makefile style build process, the compiler might be invoked next to the source files and not in the build directory – and gcovr doesn't really have good heuristics for that case. This would explain that the subdir doesn't work. I don't actually think the `--object-directory` would help then. But I don't understand the behaviour 100% either. – amon Apr 11 '19 at 16:02
  • @amon Given the update (see **Edit #2** above), do you think there's some filter setting that might help? – Tiberius Apr 11 '19 at 17:32

0 Answers0