gcov 没有为头文件生成覆盖率信息

gcov is not generating coverage information for header files

我正在使用 gcov for the first time and I'm having a problem which is similar to the one reported in this thread。但是,根据该线程中的评论,我无法解决我的问题。

我正在尝试测量 KMyMoney-4.6.4 中具体测试用例的覆盖率,即测试文件 "mymoneyaccounttest.cpp" 中的 "testConstructor"。此测试用例使用以下方法,该方法在头文件"mymoneyaccount.h" 中并具有可执行代码:

 const QString& institutionId(void) const {
    return m_institution;
  }

因此,我构建程序和测试,然后执行: gcov mymoneyaccount.cpp

在显示的覆盖信息中,我得到:

... 文件 'mymoneyaccount.cpp' 393 行 executed:8.91% 创建 'mymoneyaccount.cpp.gcov'

文件'mymoneyaccount.h' 第 executed:25.00% 行,共 4 行 创建 'mymoneyaccount.h.gcov' ...

"mymoneyaccount.cpp.gcov"中的覆盖信息是可以的。相比之下,"mymoneyaccount.h.gcov" 显示:

    6:   81:class KMM_MYMONEY_EXPORT MyMoneyAccount : public MyMoneyObject, public MyMoneyKeyValueContainer
    ...
    -:  192:  const QString& institutionId(void) const {
    -:  193:    return m_institution;
    -:  194:  }
    ...
    -:  272:  int accountCount(void) const {
#####:  273:    return m_accountList.count();
    -:  274:  };

也许我错了,但这个结果意味着 gcov 没有将 "return m_institution;" 视为可执行代码,而将 "return m_accountList.count()" 视为可执行代码。此外,它在 class 声明的行中显示“6”,因此该文件包含覆盖率信息,但不是我所期望的。

我不得不说,问题可能与文件名和目录有关:

1- 目标文件在 "CMakefiles/kmm_mymoney.dir" 中创建,以“.cpp.o”结尾,例如 mymoneyaccount.cpp.o。因此,"gcno" 和 "gcda" 文件以名称 "mymoneyaccount.cpp.gcno" 和 "mymoneyaccount.cpp.gcda" 创建(当然,在目录 "CMakefiles/kmm_mymoney.dir" 中)。

2- 当我执行时: gcov -o CMakeFiles/kmm_mymoney.dir mymoneyaccount.cpp gcov 给出以下错误:

mymoneyaccount.gcno:无法打开笔记文件

所以我必须重命名这些文件: mv mymoneyaccount.cpp.gcno mymoneyaccount.gcno mv mymoneyaccount.cpp.gcda mymoneyaccount.gcda

最后,我还有一个问题。当我在包含测试用例的文件中执行 gcov 时,我的意思是 "gcov mymoneyaccounttest.cpp" 而不是 "gcov mymoneyaccount.cpp",我也获得了一个 "mymoneyaccount.h.gcov" 文件,但覆盖率信息更差:

#####:   81:class KMM_MYMONEY_EXPORT MyMoneyAccount : public MyMoneyObject, public MyMoneyKeyValueContainer

无论如何,问题是:我应该在实现文件 "mymoneyaccount.cpp" 上执行 "gcov" 还是在测试文件 "mymoneyaccounttest.cpp" 中执行?

抱歉太长了。谢谢。

非常感谢托尼!! link 有解决方案。我刚刚将优化从 -O2 更改为 -O0,现在结果是:

1: 192: const QString& institutionId(void) const { 
1: 193:     return m_institution; 
-: 194: } 

我必须注意,要获得 "mymoneyaccount.cpp.gcov" 我执行 "gcov mymoneyaccount.cpp",但要获得 "mymoneyaccount.h.gcov" 我必须执行 "gcov mymoneyaccounttest.cpp"。你知道为什么吗?两个文件都包含 "mymoneyaccount.h".

has coverage information but not what I was expecting.

这可能是一个 XY 问题,因为您认为您的程序以您相信的方式执行,但它运行起来完全不同.

我将向您展示一个非常简单的程序:

class Example
{
    private:
        int value;

    public:
        Example(const Example& in): value(in.value)
        {
            std::cout << "Here we copy" << std::endl;
        }

        Example(int _value): value(_value)
        {
            std::cout << "Runs with default" << std::endl;
        }

        Example( Example&& in): value( in.value)
        {
            std::cout << "Moved away" << std::endl;
        }

        void show()
        {
            std::cout << "value " <<  value << std::endl;
        }
};

Example GetIt()
{
    return Example(2);
}

int main()
{
    Example ex(Example(1));
    ex.show();

    std::cout << "----------------" << std::endl;

    Example ex2( GetIt());
    ex2.show();
}

输出为:

Runs with default
value 1
Runs with default 
value 2

如您所见,没有像您预期的那样调用复制构造函数,也没有调用移动构造函数。构造被简单地省略了!那么你期望 gcov 打印出什么?简单地说,它打印了对带有 int 参数的构造函数的直接调用的调用。没有别的!

你说:

I require to have the full coverage information...

根本没有办法得到更多的信息作为真相!

如果您的期望与您从分析工具中得到的完全不同,请检查您的假设是否正确。对于 my 的期望,工具 gcov 和 gprof 非常好,代码的检测工作近乎完美。但是将优化掉的代码不会生成任何 debug/profiling/coverage 信息。对于调试,它并不总是正确的,因为较新版本的 gcc 会生成一些元信息,这些元信息为原始源代码提供 link ,如果代码不再存在于可执行文件中,也可以设置断点。但是对于省略的构造函数,在调试时也没有任何东西存在,因为程序流只是改变了!没有 cout,没有调用构造函数,也没有 profiling/coverage 的进一步信息。代码根本没有被执行,也根本没有被使用。如您所见, cout 没有被调用!这只是告诉您代码是 "modified" 以您编码的其他方式运行!

我的例子只展示了优化的一个方面!这只是省略!还有很多其他的优化步骤和策略,还有O0!请注意,我的代码是使用 O0 编译的,而复制构造已被移走!

提示:

  • 如果您的 debug/coverage/profiling 看起来与您的预期不同:查看程序集以找出真正执行的内容以及涉及哪些源代码行。您可以为此调用 objdump 来混合源代码和汇编程序!

  • 如果您缩减优化器,请记住您的程序只是运行不同的代码。没有 "intelligent" 解释就无法得出结果。这需要一点经验如何处理这样的数据。

  • 如果您真的需要 "full" 信息,请问为什么!

  • 如果您认为您没有获得足够的程序执行路径信息,您应该很高兴!通常这恰好告诉你,你的执行通过优化缩短了一点。

  • 并且如果您没有获得关于单个 line/method 的分析信息:只需查看 uses/calls 此功能所在的块。主要是耗时太短,再查也没用。

我想完成我给@Klaus 的回答。

“-O2 -g”和“-O2”这两个组合给出了此方法的以下覆盖信息(我插入消息只是为了确保该方法在测试中被执行):

-:  192:  const QString& institutionId(void) const {
1:  193:    std::cout << "Inside institutionId\n";
-:  194:    return m_institution;
-:  195:  }

这意味着第 192 和 194 行不被认为是可执行的,而只是 cout。标志 -g 不影响结果(至少在这种情况下)。

如果我使用“-O0”构建程序,结果是:

1:  192:  const QString& institutionId(void) const {
1:  193:    std::cout << "Inside institutionId\n";
1:  194:    return m_institution;
-:  195:  }