0

I have a project that has a lot of source files. They are then compiled to .o objects and in the end, linked with main.o to make main.exe. I'm compiling all files (source1.c, source2.c, main.c) with --coverage -O0 using gcc, generating .o and .gcno for each file. Then, I link everything together and call main.exe, generating .gcda files, again, for each object file.

When I run gcov source1.o source2.o main.o I get a warning? error? for every function twice:

./tests/source1.gcno:'build' has arcs to entry block
./tests/source1.gcno:'build' has arcs from exit block

The problem is that this fills the terminal with these messages and takes a long time to finish. All I could find in SO was this, so I checked the version for both gcc and gcov:

$ gcc --version
gcc.exe (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcov --version
gcov (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.

And yet, that question didn't help me so much. I'm using the MinGW-w64 installed with chocolatey. I also couldn't find any examples on the internet using gcov with multiple source files, hence the title.

I don't know exactly what is wrong, since I've been stuck with this problem for a week now. My project does run and produces code coverage, but these thousands and thousands of warnings are making my CI messages unnecessarily long.

Also, I would appreciate if anyone could explain better what the warning message means.

Edit:

Example of the flags that I'm using to compile main.c:

gcc -Wall -Werror --coverage -O0 -lgcov -I ./tests/include -I ./src -c ./tests/main.c -o ./tests/build/main.o
LeoVen
  • 632
  • 8
  • 18
  • I actually have the same issue (win10, using mingw_64-8.1 from Qt), I run gcov on the _.gcno_ files though. Taking ages to finish. I'm really looking forward to answers to this question. – tooEarlyToGetUp Apr 20 '22 at 11:36

1 Answers1

2
gcov source1.o source2.o main.o

No. That doesn't work that way. It works like this:

  • You compile your program with --coverage
    • --coverage inserts all over your program statements like fprintf(<some log file>, "I was here")
    • such fprintf statements are generated on every entry/exit function, on every if entry/exit, on every flow entry/exit, etc.
  • Then you execute your program.
    • During your program execution the fprintf statements are executed.
    • A log file is created that contains "I was here" information from all over your executable.
  • Then your program terminates.
  • Then you execute gcov on the resulting log file.

I also couldn't find any examples on the internet using gcov with multiple source files

@edit from single source file to three source files.

Example: Let's take a some source files 1.c 2.c 3.c and a makefile:

cat >1.c <<EOF
main() {
    func(0);
}
EOF

cat >2.c <<EOF
int func(int a) {
    if (a) {
        printf("Never here\n");
    }
    printf("Always here\n");
}
EOF

cat >3.c <<EOF
int func2(int b) {
    if (b == 1) {
        printf("func2\n");
    }
    printf("func2 no \n");
    return b + 1;
}
EOF

cat >Makefile <<EOF
CFLAGS=--coverage
a.out: 1.o 2.o 3.o
    $(CC) $(CFLAGS) $^

EOF

We compile those and execute:

$ make
cc --coverage   -c -o 1.o 1.c
cc --coverage   -c -o 2.o 2.c
cc --coverage   -c -o 3.o 3.c
cc --coverage 1.o 2.o 3.o

And then we run the executable:

$ ./a.out
Always here

New files are created:

$ ls
1.c  1.c.gcov  1.gcda  1.o  2.c  2.c.gcov  2.gcda  2.o  3.c  3.c.gcov  3.gcda  3.o  Makefile  a.out*

Then you can execute gcov on those files:

$ gcov *.gcno
File '1.c'
Lines executed:100.00% of 2
Creating '1.c.gcov'

File '2.c'
Lines executed:80.00% of 5
Creating '2.c.gcov'

File '3.c'
Lines executed:0.00% of 5
Creating '3.c.gcov'

And you can inspect the resulting 1.c.gcov file.

Executing gcov on object files doesn't make sense. gcov parses information from an execution. -lgcov is not needed - --coverage is all that is needed (--coverage does -lgcov by itself).

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Even when I was executing `gcov` on object files, I was still getting the coverage results. Now I changed to `.gcda` files and I'm still getting the same results. I also removed `-lgcov`. I also couldn't find your example very useful because > "I also couldn't find any examples on the internet using gcov with multiple source files, hence the title." – LeoVen Jun 23 '20 at 02:07
  • ? You just compile the executable from multiple source files, and then run gcov on resulting files.. `I also couldn't find any examples on the internet using gcov with multiple source files` .... ok. gcov "finds" it's files automagically, so if you give object files to it, it will try to search for gcda files in the same directory as object files. So if you do `gcov file.o` gcov will search for `file.gcno` and `file.o.gcno` and similar... The count of files do not matter, just gcov has to find the resulting files. – KamilCuk Jun 23 '20 at 07:01