Reputation: 11
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:}
Upvotes: 0
Views: 8587
Reputation: 86
You can run coverage runs in separate directories. Then run
lcov --capture --rc lcov_branch_coverage=1 --directory dir_1 --config-file ./lcovrc --output coverage_1.info
lcov --capture --rc lcov_branch_coverage=1 --directory dir_2 --config-file ./lcovrc --output coverage_2.info
then merge file (line coverage or branch coverage):
coverage_1.info
and coverage_2.info
If needed generate final htmp report
genhtml --branch-coverage --output ./generated-coverage/ merged_coverage.info
Upvotes: 1
Reputation: 57646
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
Upvotes: 6