How to use gcovr with source files outside the current/build/run directory?
Asked Answered
B

2

8
mkdir -p /tmp/build &&
cd /tmp/build &&
mkdir -p /tmp/src &&
echo "int main(){return 0;}" > /tmp/src/prog.c &&
gcc --coverage -o prog /tmp/src/prog.c &&
./prog &&
gcovr -v -r .

will output an empty report.

Scanning directory . for gcda/gcno files...
Found 2 files (and will process 1)
Processing file: /tmp/build/prog.gcda
Running gcov: 'gcov /tmp/build/prog.gcda --branch-counts --branch-probabilities --preserve-paths --object-directory /tmp/build' in '/tmp/build'
Finding source file corresponding to a gcov data file
  currdir      /tmp/build
  gcov_fname   #tmp#src#prog.c.gcov
               ['        -', '    0', 'Source', '/tmp/src/prog.c\n']
  source_fname /tmp/build/prog.gcda
  root         /tmp/build
  fname        /tmp/src/prog.c
Parsing coverage data for file /tmp/src/prog.c
  Filtering coverage data for file /tmp/src/prog.c
Gathered coveraged data for 0 files
------------------------------------------------------------------------------
                           GCC Code Coverage Report
Directory: .
------------------------------------------------------------------------------
File                                       Lines    Exec  Cover   Missing
------------------------------------------------------------------------------
------------------------------------------------------------------------------
TOTAL                                          0       0    --%
------------------------------------------------------------------------------

However if I manually run

gcov /tmp/build/prog.gcda --branch-counts --branch-probabilities --preserve-paths --object-directory /tmp/build

I get correct results

File '/tmp/src/prog.c'
Lines executed:100.00% of 1
No branches
No calls
Creating '#tmp#src#prog.c.gcov'

It seems that gcovr did not extract the coverage from the otherwise correct gcov output. This only happens if the source file is outside the current directory (same as build directory, same as output directory, same as run directory), and gcc ics called with an absolute path to the source file.

How can I fix this?

Edit

Fixed in upstream gcovr for relative paths, but looks like a bug for absolute paths.

See https://github.com/gcovr/gcovr/issues/169.

Bellyache answered 12/5, 2017 at 10:0 Comment(2)
Instead of giving all those mkdir you should explain the directory structure directly in your question. Explaining where the obj and source files are placedCandiot
@Vikas I like it better if there is runable code that reproduces the problem. (At least if the question is this kind of "bug or user error?")Bellyache
C
6

What I understood from your code up there is that you made everything and ran the program but you are still inside build directory where the object file resides.

So, what you need to understand is:

gcovr -v -r <path>

this -r flag takes the root directory, which means the parent directory inside which the source and object directory resides. So that it can trace them both and generate coverage data and whatever else you want it to generate.
Try doing that and it will work.

For your understanding:

The .gcno files that gets generated after compilation is just the flowchart kind of data for that particular source file.
Then later when you execute the program, a .gcda file gets generated for each source file. This file contains real coverage data, but for gcovr all these three files are necessary (.gcno, .gcda, sourceFile)

Hope it helped. :)

update:
Back with the work around
You can supply your coverage data location as a pure arg (no option) and point the root to your sources.

gcovr .../path/To/GCDA -r .../path/to/src/ [rest desired flags]

This will solve your problem for sure.
Worked for me in covering my projects.

Candiot answered 17/5, 2017 at 12:12 Comment(10)
The .gcno files already contain the paths where the sources can be found. (Do a strings on an .gcno file.)Bellyache
It is good practice to keep sources and build directory separate, so gcovr should support this.Bellyache
yes, I am talking about the root directory here. which contains build and source directory. Also, always add an extra slash after last directory name in path.Candiot
I understand, but I want to use gcovr in a Makefile, and I want to make no assumptions about where I am building. (How to calculate that common root directory? What if it contains many more unrelated sources and gcov files? Here it is /tmp/, do I really want to feed all of /tmp/ int gcovr?!?No!) - While I'm doing this, lcov seems the superior solution for my problem. (Works in the build directory, finds the sources by (effectively) inspecting the .gcno files.)Bellyache
I have done it for few huge projects which use cmake. I was making the build by passing --coverage flag in command so that it works with the usual build cmake file. There were thousands of source files, so I had to give the closest possible parent directory which has both obj and src directory inside it. gcovr traces all the gcda files and then only those source files which are relevant to all gcdaCandiot
But there's one more work around for it. I will get back to you after monday, as I will have to check on my previous work.Candiot
it doesn't requires to have both source and obj just below the directory we passed. It can be anywhere down the line. usually obj files are created using the same structure as source files, when we use automated building. So, it works fine.Candiot
@Bellyache updated the answer for work around, do check it. :)Candiot
I have my source files in multiple directories, how to provide multiple values to -r (--root) ? comma/semicolon ?Remanent
@Remanent It's been a long time but if my memory serves me right then you should either be working from the root directory as explained, it will be like the one parent directory for everything or else you can simply merge separately generated reports later on.Candiot
C
3

Gcovr only generates reports for source files within your project. This is intended to exclude coverage from library headers etc.

The question is, which files are in your project? This is determined by the -r root path.

If you are in /tmp/build and root is . aka /tmp/build and the source file is /tmp/src/prog.c, then that source file is clearly outside of your project. In the verbose output, gcovr will report Filtering coverage data for file /tmp/src/prog.c.

If you are in /tmp/build and root is .. aka /tmp and the source file is /tmp/src/prog.c, then that source file is within the project.

If you are in /tmp/build and root is . aka /tmp/build and the source file is ../src/prog.c, then gcovr seems to do something questionable: It joins the file name with the current directory and checks that. So we actually see /tmp/build/../src/prog.c. As far as gcovr is concerned, that's within your project. It seems this behaviour is necessary to include code that is symlinked into a project.

You can disable this “is the source within the project?” filter by providing your own, better filter. For example, you can ask gcovr to only report coverage for sources under /tmp/src:

gcovr -r . -f /tmp/src
Carousal answered 9/1, 2018 at 22:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.