【问题标题】:gcov is not generating coverage information for header filesgcov 没有为头文件生成覆盖信息
【发布时间】:2015-11-26 14:35:25
【问题描述】:

我第一次使用gcov,遇到的问题与thread 中报告的问题类似。但是,在该线程中的 cmets 之后,我无法解决我的问题。

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

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

所以,我构建了程序和测试,然后执行: gcov mymoneyaccount.cpp

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

... 文件“mymoneyaccount.cpp” 执行的行数:393 的 8.91% 创建“mymoneyaccount.cpp.gcov”

文件“mymoneyaccount.h” 执行的行数:4 的 25.00% 创建“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()”视为可执行代码。此外,它在类声明的行中显示“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”还是在测试文件“mymoneyaccounttest.cpp”中执行“gcov”?

抱歉,篇幅较长。谢谢。

【问题讨论】:

  • Possibly related。请注意,类定义中定义的成员函数是隐式内联的。 See also gcov inline docs.
  • 非常感谢托尼!!该链接有解决方案。我刚刚将优化从 -O2 更改为 -O0 现在结果是: 1: 192: const QString& authorityId(void) const { 1: 193: return m_institution; -: 194: } 我必须注意,要获得“mymoneyaccount.cpp.gcov”,我执行“gcov mymoneyaccount.cpp”,但要获得“mymoneyaccount.h.gcov”,我必须执行“gcov mymoneyaccounttest.cpp”。你知道为什么吗?这两个文件都包含“mymoneyaccount.h”。

标签: c++ qt gcc gcov


【解决方案1】:

我想完成我给@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:  }

【讨论】:

    【解决方案2】:

    有报道信息,但不是我所期望的。

    这可能是一个 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 参数的构造函数的直接调用的调用。没有别的!

    你说:

    我需要完整的覆盖信息...

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

    如果您的期望与您从分析工具中得到的完全不同,请检查您的假设是否正确。对于 我的 期望,工具 gcov 和 gprof 非常好,并且代码检测工作几乎完美。但是将优化掉的代码不会生成任何调试/分析/覆盖信息。使用调试并不总是如此,因为较新版本的 gcc 会生成一些元信息,这些信息会提供指向原始源代码的链接,如果代码不再存在于可执行文件中,也可以设置断点。但是对于省略的构造函数,在调试时也没有任何内容,因为程序流程只是简单地改变了!没有cout,没有调用构造函数,也没有关于分析/覆盖的更多信息。代码根本没有被执行,也根本没有被使用。如您所见,cout 没有被调用!这只是告诉您代码已“修改”为以您编写的其他方式操作!

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

    提示:

    • 如果您的调试/覆盖/分析看起来与您的预期不同:查看程序集以找出真正执行的内容以及涉及哪些源代码行。您可以调用 objdump 来获取源代码和汇编程序的混合!

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

    • 如果您真的需要“完整”信息,请问为什么!

    • 如果您认为您没有获得足够的关于程序执行路径的信息,您应该很高兴!通常这会准确地告诉您,通过优化可以缩短执行时间。

    • 如果您没有在单行/方法上获得分析信息:只需查看使用/调用此功能的块。大多数情况下,时间消耗很短,进一步调查是没有用的。

    【讨论】:

    • 非常感谢@Klaus 的详细回答。就我而言,对于实际执行的方法(我什至打印了一条消息以确保这一点),gcov 没有提供预期的覆盖率信息。当我将 -O2 变为 -O0 时,提供了该信息。该程序已使用标志“-g”进行编译以进行调试。我可以检查这是否是您指出的问题。也许“我需要完整的覆盖信息......”是不正确的:我需要拥有已执行代码的所有覆盖信息。
    【解决方案3】:

    非常感谢托尼!!该链接有解决方案。我刚刚将优化从 -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”。

    【讨论】:

    • 更改优化器级别以查看预期结果并不总是正确的解决方案!如果您的代码正常使用 O2,您还必须使用 O2 检查您的代码。否则,生产的执行路径与测量/测试的执行路径不同。也许 O2 代码被内联,而 O0 不使用!
    • 感谢您的回答@Klaus。我一直在谷歌上搜索 gcov 和优化,发现这篇文章:link 你认为我应该使用一些标志而不是更改优化级别吗?我需要完整的报道信息...
    猜你喜欢
    • 1970-01-01
    • 2015-02-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2011-06-06
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    相关资源
    最近更新 更多