当同一源文件的两个可执行文件 运行 时,.gcda 文件覆盖信息未更新
.gcda file coverage info not getting updated when two executables run for same source file
共有三个文件 u1.c , u2.c 和 common.c
ut1.c
的内容
#include<stdio.h>
void fun1();
int main(){
fun1();
}
ut2.c
的内容
#include<stdio.h>
void fun2();
int main(){
fun2();
}
common.c
的内容
void fun1(){
printf("fun1\n");
}
void fun2(){
printf("fun2\n");
}
编译步骤:-
gcc -Wall -fprofile-arcs -ftest-coverage ut1.c common.c -o ut1
gcc -Wall -fprofile-arcs -ftest-coverage ut2.c common.c -o ut2
执行步骤:-
./ut1
./ut2
现在 运行 gcov common.c 只有 fun2 报道即将到来。
-: 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:}
这是因为您正在编译 common.c
两次。
当运行你的ut1和ut2程序时,我们可以看到如下警告(使用GCC 10测试):
$ ./ut1
fun1
$ ./ut2
fun2
libgcov profiling error:/tmp/gcov-test/common.gcda:overwriting an existing profile data with a different timestamp
每次在启用覆盖率的情况下进行编译时,GCC 都会为覆盖率数据分配一个校验和。 gcov 工具主要使用此校验和来确保 gcno 文件和 gcda 文件匹配。在编译 ut1 和 ut2 时,会使用不同的校验和。因此,ut2 不会 附加 覆盖数据,而是会看到无效的校验和并将 覆盖 数据。
解决方法是将common.c
作为一个单独的编译单元,link将它与ut1和ut2一起处理。例如:
# 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
那么,gcov 输出应该符合预期:
-: 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:}
如果您无法更改项目的编译方式,则可以使用 lcov 或 gcovr 等工具收集覆盖率数据,然后将其合并。例如,gcovr 的工作流程如下:
编译ut1,执行,将覆盖数据保存为gcovr JSON报告:
gcc -Wall --coverage ut1.c common.c -o ut1
./ut1
gcovr --json ut1.json
rm *.gcda *.gcno
编译ut2,执行,将覆盖数据保存为gcovr JSON报告:
gcc -Wall --coverage ut2.c common.c -o ut2
./ut2
gcovr --json ut2.json
创建合并报告:
gcovr -a ut1.json -a ut2.json --html-details coverage.html
虽然 gcovr 无法输出 gcov 样式的文本报告,但它可以将覆盖率显示为 HTML:
此答案的完整代码位于 https://gist.github.com/latk/102b125dff160484f93d8997204fc201
您可以在单独的目录中 运行 覆盖 运行。那么运行
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
然后合并文件(行覆盖或分支覆盖):
coverage_1.info
和 coverage_2.info
如果需要生成最终的 htmp 报告
genhtml --branch-coverage --output ./generated-coverage/ merged_coverage.info
共有三个文件 u1.c , u2.c 和 common.c
ut1.c
的内容#include<stdio.h>
void fun1();
int main(){
fun1();
}
ut2.c
的内容#include<stdio.h>
void fun2();
int main(){
fun2();
}
common.c
的内容void fun1(){
printf("fun1\n");
}
void fun2(){
printf("fun2\n");
}
编译步骤:-
gcc -Wall -fprofile-arcs -ftest-coverage ut1.c common.c -o ut1
gcc -Wall -fprofile-arcs -ftest-coverage ut2.c common.c -o ut2
执行步骤:-
./ut1
./ut2
现在 运行 gcov common.c 只有 fun2 报道即将到来。
-: 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:}
这是因为您正在编译 common.c
两次。
当运行你的ut1和ut2程序时,我们可以看到如下警告(使用GCC 10测试):
$ ./ut1
fun1
$ ./ut2
fun2
libgcov profiling error:/tmp/gcov-test/common.gcda:overwriting an existing profile data with a different timestamp
每次在启用覆盖率的情况下进行编译时,GCC 都会为覆盖率数据分配一个校验和。 gcov 工具主要使用此校验和来确保 gcno 文件和 gcda 文件匹配。在编译 ut1 和 ut2 时,会使用不同的校验和。因此,ut2 不会 附加 覆盖数据,而是会看到无效的校验和并将 覆盖 数据。
解决方法是将common.c
作为一个单独的编译单元,link将它与ut1和ut2一起处理。例如:
# 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
那么,gcov 输出应该符合预期:
-: 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:}
如果您无法更改项目的编译方式,则可以使用 lcov 或 gcovr 等工具收集覆盖率数据,然后将其合并。例如,gcovr 的工作流程如下:
编译ut1,执行,将覆盖数据保存为gcovr JSON报告:
gcc -Wall --coverage ut1.c common.c -o ut1 ./ut1 gcovr --json ut1.json rm *.gcda *.gcno
编译ut2,执行,将覆盖数据保存为gcovr JSON报告:
gcc -Wall --coverage ut2.c common.c -o ut2 ./ut2 gcovr --json ut2.json
创建合并报告:
gcovr -a ut1.json -a ut2.json --html-details coverage.html
虽然 gcovr 无法输出 gcov 样式的文本报告,但它可以将覆盖率显示为 HTML:
此答案的完整代码位于 https://gist.github.com/latk/102b125dff160484f93d8997204fc201
您可以在单独的目录中 运行 覆盖 运行。那么运行
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
然后合并文件(行覆盖或分支覆盖):
coverage_1.info
和 coverage_2.info
如果需要生成最终的 htmp 报告
genhtml --branch-coverage --output ./generated-coverage/ merged_coverage.info