测量在Python进程中调用的C库覆盖率

3 投票
1 回答
512 浏览
提问于 2025-04-16 16:45

让我先举个例子——在Python中调用库代码。

这是库代码(编译成库 libfoolib):

#include <stdio.h>

void bar()
{
    printf("bar\n");
}

void foo()
{
    printf("foo\n");
}

这是调用它的Python代码:

#!/usr/bin/python25
import sys
import libfoolib
import processing

def callFoo():
    libfoolib.foo()

libfoolib.bar()

process = processing.Process(target=callFoo)
process.start()

当库使用 -ftest-coverage-fprofile-arcs 编译时,编译器会生成 gcno 文件,而当执行Python代码时,gcda 文件也会被生成。问题是,这个文件只包含了在Python进程分叉之前调用的 bar 函数的覆盖率数据。如果 foo 函数也在Python处理调用之外被调用,那么一切就正常了。

这是我在生成的覆盖率数据上运行 gcov 工具时得到的结果:

        -:    0:Source:/codeCoverageTests/pythonSIP/foo.c
        -:    0:Graph:debug/CMakeFiles/fooLib.dir/foo.c.gcno
        -:    0:Data:debug/CMakeFiles/fooLib.dir/foo.c.gcda
        -:    0:Runs:4
        -:    0:Programs:1
        -:    1:#include <stdio.h>
        -:    2:
        -:    3:void bar()
function bar called 4 returned 100% blocks executed 100%
        4:    4:{
        4:    5:    printf("bar\n");
call    0 returned 100%
        4:    6:}
        -:    7:
        -:    8:void foo()
function foo called 0 returned 0% blocks executed 0%
    #####:    9:{
    #####:   10:    printf("foo\n");
call    0 never executed
    #####:   11:}
        -:   12:

我想问的问题是:“我的 foo 的覆盖率数据在哪里?”

关于环境的一些详细信息:

  • CentOS 5.4
  • gcc: 4.1.2 20080704 (Red Hat 4.1.2-46)
  • CMake构建(版本 2.8.0)
  • Python 2.5
  • Python与C之间使用SIP(版本 4.7.4)

1 个回答

1

问题在于,Python的处理库使用了os._exit来退出程序。这种退出方式有个缺点,就是不会调用正常的清理程序。也就是说,程序在结束时没有机会去做一些必要的清理工作。实际上,覆盖率工具会在程序退出时收集数据并写入,这个过程是在正常的清理程序中进行的。由于这些原因,子进程没有机会写出它的数据,所以调用foo的结果也就没法被记录下来。

为了解决这个问题,我在程序结束前手动调用了__gcov_flush。因为这是一个静态库,所以需要写一个小的C语言代码来完成这个任务。

撰写回答