如何合并多个版本的gcda文件?

时间:2014-07-31 12:55:23

标签: c++ gcov lcov

我正在使用gcov来获取我的应用程序的覆盖信息。但是,我的应用程序有3个实例同时运行,创建3个版本的“gcda”文件。有没有办法在我的覆盖率信息文件中合并不同版本的相同“gcda”文件。

我想将覆盖范围信息仅作为一个实例。

1 个答案:

答案 0 :(得分:0)

我一直在研究相同的问题,这就是我所发现的。 TL; DR是,有可能,在最佳情况下,只需注意编译顺序即可,并且以最一般(最复杂)的方式使用gcov-tool merge命令,但这并不是开箱即用的,它需要一些专用的设置才能使其正常工作。

代码

在我的示例中,我有一个库文件lib.cpp,具有两个功能:

#include <iostream>

void five(int n) {
        if (n > 5) {
                std::cout << n << " is greater than five" << std::endl;
        } else {
                std::cout << n << " is not greater than five" << std::endl;
        }
}

void ten(int n) {
        if (n > 10) {
                std::cout << n << " is greater than ten" << std::endl;
        } else {
                std::cout << n << " is not greater than ten" << std::endl;
        }
}

然后我有两个程序,每个程序都调用其中一个功能five.cpp

#include <iostream>
#include "lib.hpp"

int main(int argc, char *argv[]) {
        if (argc != 2) {
                std::cerr << "usage: " << argv[0] << " <n>" << std::endl;
                return 2;
        }

        int n = std::stoi(argv[1]);
        five(n);
        return 0;
}

ten.cpp

#include <iostream>
#include "lib.hpp"

int main(int argc, char *argv[]) {
        if (argc != 2) {
                std::cerr << "usage: " << argv[0] << " <n>" << std::endl;
                return 2;
        }

        int n = std::stoi(argv[1]);
        ten(n);
        return 0;
}

假设代码位于/tmp/merge-gcov目录中。

捕获覆盖率

启用覆盖率捕获可以像

g++ -O0 --coverage -o five five.cpp lib.cpp

将创建lib.gcnofive.gcno文件。运行five程序时,它将创建/tmp/merge-gcov/lib.gcda/tmp/merge-gcov/five.gcda。请注意,这些gcda路径被硬编码到二进制文件中(但可以稍后对其进行操作)。

./five 1
./five 12       # Results from multiple runs will accumulate in gcda files
mkdir report
gcovr -r . --html --html-details --output report/report.html
firefox report/report.html 

多次冲突

到目前为止,一切都很好。但是,如果我们现在也以相同的方式编译ten程序

g++ -O0 --coverage -o ten ten.cpp lib.cpp

然后它将创建一个lib.gcno,它比编译lib.gcno的{​​{1}}要新,并且与之不同。这意味着无论何时fivefive都在另一个之后运行,它将检测到ten文件不符合其期望(gcno起源)并重置文件内容,从而丢弃任何累积的先前内容。

可以通过先分别编译lib.gcda文件来避免这种情况,例如

lib.cpp

现在g++ -O0 --coverage -c lib.cpp g++ -O0 --coverage -o five lib.o five.cpp g++ -O0 --coverage -o ten lib.o ten.cpp five将共享相同的ten,并且它们都将累积lib.gcno

因此,如果在链接二进制文件之前小心所有共享代码仅编译一次,则最好从多个二进制文件中获取覆盖结果。

共享代码的不同编译方式

但是如果我们想以不同的方式编译库怎么办?也许我们想编译一个禁用了调试代码的版本,然后启用一个版本来验证代码在两种情况下都可以工作。然后,先前的解决方案将无法正常工作,而策略是将每个二进制文件放入其自己的目录中,然后在以后合并这些目录。

lib.gcda

注意,我说过gcda路径之前已经过硬编码了吗?您可以只使用它,运行每个二进制文件,然后移动g++ -O0 --coverage -c lib.cpp -DENABLE_DEBUG g++ -O0 --coverage -o five lib.o five.cpp mkdir gcov-five mv *.gcno gcov-five/. 文件后缀。或者,您可以设置环境变量以使程序使用不同的目录。 GCOV_PREFIX_STRIP将从完整路径的开头砍掉目录,例如*.gcdaGCOV_PREFIX_STRIP=1成为/tmp/merge-gcov/lib.gcda。 GCOV_PREFIX变量将放在路径的前面。

merge-gcov/lib.gcda