There are three files u1.c , u2.c and common.c
content of ut1.c
#include<stdio.h>
void fun1();
int main(){
fun1();
}
content of ut2.c
#include<stdio.h>
void fun2();
int main(){
fun2();
}
content of common.c
void fun1(){
printf("fun1\n");
}
void fun2(){
printf("fun2\n");
}
Compilation steps:-
gcc -Wall -fprofile-arcs -ftest-coverage ut1.c common.c -o ut1
gcc -Wall -fprofile-arcs -ftest-coverage ut2.c common.c -o ut2
Execution steps:-
./ut1
./ut2
Now when running gcov common.c only fun2 coverage is coming.
-: 0:Source:common.c
-: 0:Graph:common.gcno
-: 0:Data:common.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:void fun1(){
-: 2: printf("fun1\n");
-: 3:}
-: 4:
1: 5:void fun2(){
1: 6: printf("fun2\n");
1: 7:}
This is because you are compiling common.c
two separate times.
When running your ut1 and ut2 programs, we can see the following warning (tested with GCC 10):
$ ./ut1
fun1
$ ./ut2
fun2
libgcov profiling error:/tmp/gcov-test/common.gcda:overwriting an existing profile data with a different timestamp
Each time when you compile with coverage enabled, GCC will assign a checksum to the coverage data. This checksum is primarily used by the gcov tool to ensure that the gcno file and gcda files match. When compiling ut1 and ut2, different checksums will be used. So instead of appending coverage data, ut2 sees the invalid checksum and will overwrite the data.
The solution is to treat common.c
as a separate compilation unit and link it with ut1 and ut2. For example:
# compile common.c
gcc -Wall --coverage -c common.c -o common.o
# compile ut1 and ut2, and link with common.o
gcc -Wall --coverage ut1.c common.o -o ut1
gcc -Wall --coverage ut2.c common.o -o ut2
Then, the gcov output should be as expected:
-: 0:Source:common.c
-: 0:Graph:common.gcno
-: 0:Data:common.gcda
-: 0:Runs:2
-: 1:#include<stdio.h>
1: 2:void fun1(){
1: 3: printf("fun1\n");
1: 4:}
-: 5:
1: 6:void fun2(){
1: 7: printf("fun2\n");
1: 8:}
If you cannot change how your project is compiled, you could collect the coverage data with a tool such as lcov or gcovr, and then merge it. For example, the workflow with gcovr would be as follows:
Compile ut1, execute it, and save the coverage data as a gcovr JSON report:
gcc -Wall --coverage ut1.c common.c -o ut1
./ut1
gcovr --json ut1.json
rm *.gcda *.gcno
Compile ut2, execute it, and save the coverage data as a gcovr JSON report:
gcc -Wall --coverage ut2.c common.c -o ut2
./ut2
gcovr --json ut2.json
Create a combined report:
gcovr -a ut1.json -a ut2.json --html-details coverage.html
While gcovr cannot output gcov-style textual reports, it can show the coverage as HTML:
Full code for this answer is at https://gist.github.com/latk/102b125dff160484f93d8997204fc201