5

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

我想以覆盖信息为例。

4

1 回答 1

5

我一直在研究同样的问题,这就是我发现的。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更新且不同的。这意味着无论何时或在另一个之后运行,它都会检测到文件不符合其预期(来自 gcno 的)并重置文件内容,从而丢弃任何累积的先前内容。lib.gcnofivefivetenlib.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

现在两者都fiveten共享相同的lib.gcno内容,并且它们都将累积lib.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/.

请注意我说过 gcda 路径之前是硬编码的?您可以忍受它,运行每个二进制文件,然后移动*.gcda文件。或者您可以设置环境变量以使程序使用不同的目录。GCOV_PREFIX_STRIP 将从完整路径的开头截取目录,例如GCOV_PREFIX_STRIP=1/tmp/merge-gcov/lib.gcda变成merge-gcov/lib.gcda. GCOV_PREFIX 变量将放在路径的前面。

export GCOV_PREFIX=/tmp/merge-gcov/gcov-five
export GCOV_PREFIX_STRIP=2
# Gives /tmp/merge-gcov/gcov-five/lib.gcda
./five 1
./five 12

# Repeat for ten
g++ -O0 --coverage -c lib.cpp -DDISABLE_DEBUG
g++ -O0 --coverage -o ten lib.o ten.cpp
mkdir gcov-ten
mv *.gcno gcov-ten/.
export GCOV_PREFIX=/tmp/merge-gcov/gcov-ten
./ten 1
./ten 12

# Combine 
gcov-tool merge --outdir merged gcov-five gcov-ten
于 2019-02-04T23:36:10.817 回答