当同一源文件的两个可执行文件 运行 时,.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 的工作流程如下:

  1. 编译ut1,执行,将覆盖数据保存为gcovr JSON报告:

    gcc -Wall --coverage ut1.c common.c -o ut1
    ./ut1
    gcovr --json ut1.json
    rm *.gcda *.gcno
    
  2. 编译ut2,执行,将覆盖数据保存为gcovr JSON报告:

    gcc -Wall --coverage ut2.c common.c -o ut2
    ./ut2
    gcovr --json ut2.json
    
  3. 创建合并报告:

    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.infocoverage_2.info

如果需要生成最终的 htmp 报告

genhtml --branch-coverage --output ./generated-coverage/ merged_coverage.info