如何处理 Coveragescanner 错误信息和建议
警告 "coutuation is different" 的意思是什么?
在进行 C/C++ 程序的编译过程中,Coco 可能会发出如下形式的警告
Warning (Squish Coco): Compilation of 'myproject/header.h': Instrumentation of source file 'myproject/header.h' is different
随后的几行。这意味着什么?
说明
在 C 和 C++ 中,源文件的内容并不完全决定它编译成哪些代码。这是因为预处理符号可以在编译时设置,并通过 #ifdef 语句等通常方式决定哪些源代码实际上被转换。
这意味着源文件可能因为不同的预处理设置而被编译多次。这可能会导致不同的编译代码,如果 Coco 参与,则可能导致同一文件的不同的节流。如果 Coco 发现这种情况,它会发出 "Instrumentation is different" 的消息。
然而,该消息只是一个警告。Coco 将文件的不同版本视为不同的文件,并在 CoverageBrowser 或报告中用末尾的数字区分它们。如果有两个版本的头文件 header.h,则可以显示为 header.h#1 和 header.h#2。
示例
接下来是一个示例,通过这个示例可以更清楚地了解发生了什么以及如何理解错误消息。首先需要一个源文件,这个文件可以根据外部设置编译成不同的代码。以下文件 header.h 是这样的源。它定义了一个函数,letter(),它的编译取决于预处理符号 A 是否定义。
#ifndef HEADER_H #define HEADER_H static inline char letter() { #ifdef A return 'a'; #else return 'b'; #endif } #endif
然后是两个使用此库的文件。一个是 a.cpp,
#include "a.h" #include "header.h" #include <iostream> void a() { std::cout << "Letter A: " << letter() << "\n"; }
另一个是 b.cpp。(这里省略了头文件 a.h 和 b.h)。
#include "b.h" #include "header.h" #include <iostream> void b() { std::cout << "Letter B: " << letter() << "\n"; }
请注意,这两个文件在本质上完全相同,并且它们本身不包含受符号 A 影响的任何代码。然而,它们都包含了 header.h。这意味着 a.cpp 和 b.cpp 的预处理版本——CoverageScanner 看到并对其进行了仪器化处理——包含了一个预处理版本的 header.h,并且它们依赖于符号 A。
最后,有一个程序,main.cpp,它使用它们两个。
#include "a.h" #include "b.h" int main() { a(); b(); return 0; }
所有这些文件都必须进行编译,但 a.cpp 和 b.cpp 必须使用不同的标志编译:对于 a.cpp,应该定义符号 A,但不应该为 b.cpp 定义。如果这个项目是用 makefile 编译的,它可能看起来像这样;
main: main.cpp a.o b.o
g++ -o main main.cpp a.o b.o
a.o: a.cpp a.h header.h
g++ -DA -c -o a.o a.cpp
b.o: b.cpp b.h header.h
g++ -c -o b.o b.cpp在这里可以看到,在 a.cpp 的编译中添加了额外的标志 -DA;它定义了符号 A。在其他构建系统中,设置将类似。
当这样的项目启用仪器化进行编译时,会发出上述警告。其全文是
Warning (Squish Coco): Compilation of 'myproject/header.h': Instrumentation of source file 'myproject/header.h' is different
Warning (Squish Coco): Source line 7 of file 'myproject/header.h' is differently instrumented in the database 'main.csmes' and 'b.o.csmes'
Warning (Squish Coco): Original:
Warning (Squish Coco): 4: inline char letter()
Warning (Squish Coco): 5: {
Warning (Squish Coco): 6: #ifdef A
Warning (Squish Coco): >>> 7: return 'a';
Warning (Squish Coco): 8: #else
Warning (Squish Coco): 9: return 'b';
Warning (Squish Coco): 10: #endif
Warning (Squish Coco): [ALL] Inconsistent instrumentations in: myproject/header.h
Warning (Squish Coco):
Warning (Squish Coco): [1/2] Source files: myproject/a.cpp
Warning (Squish Coco): [1/2] Distinct define flags: -DA
Warning (Squish Coco):
Warning (Squish Coco): [2/2] Source files: myproject/b.cpp
Warning (Squish Coco):
Warning (Squish Coco): [ALL] Common instrumentation options: --cs-combine-switch-cases
Warning (Squish Coco): --cs-count
Warning (Squish Coco): --cs-function-coverage
Warning (Squish Coco): --cs-line-coverage
Warning (Squish Coco): --cs-mcc在这里可以看到
- 第一行显示错误发生在编译文件
header.h期间。 - 第二行显示,当从文件
b.o.csmes中的信息合并到文件main.csmes中时发现的问题,并且它发生在第 7 行。实际上发生的事情是,最初,
main.csmes中没有包含任何有关header.h的信息。然后在链接步骤期间,合并了a.o.csmes。它包含关于定义了符号A的版本的header.h的信息。然后,也合并了b.o.csmes——包含了一个不同的版本的header.h。这导致了不一致性。 - 接下来的几行显示了不同的仪器化行:它是带有
return 'a';的行和只有定义了A时才部分包含的代码的第一行。此行的前后各有三行也被显示出来。上下文行的数量可以通过标志
–cs-verbose-source-lines设置。 - 这些差异可能是由于编译器选项引起的。以下从以
[ALL]开头的第一行开始的几行,总结了对选项的易于阅读的格式。总结包括几个部分,每个部分都由方括号中的表达式作为前缀。前缀可以是
[ALL]或类似[1/2]类似的内容。以[ALL]开头的行引用所有文件,而其他行引用一组组编译了相同命令行选项的文件。第一个数字是文件组的编号,第二个是所有文件组的编号。这意味着[1/2]指的是两个组中的第一个组。所有文件组部分具有相同的格式:首先有一行列出了组的 内容。在我们的例子中,第一个组(也是第二个)只包含一个文件
Warning (Squish Coco): [1/2] Source files: myproject/a.cpp
然后列出唯一的定义标志,即那些不在所有组中出现的标志。在第 个组中,这是预料之中的,因为它只为文件
a.cpp定义了符号A。第二个组没有独特的标志。实际上,每个组都可以为每种命令行选项列出四种类型
Distinct define flags:定义编译器符号的标志。不同的包含目录:这是用于定义#include在哪些目录中查找头文件的标志。 (目录按字母顺序排序,因此依赖于包含路径顺序的罕见错误无法通过这种方式捕获。)不同的仪器选项:这用于 coveragescanner 选项。不同的编译器标志(其他):用于其他标志。
在文件组和它们的选项之后,列出了所有源文件共有的命令行选项,并带有前缀
[ALL]。在我们的示例中,只列出了仪器选项。
Coco v7.2.0©2024 The Qt Company Ltd.
Qt 和相应的标志是芬兰和/或其他国家 Qt Company Ltd. 的商标。所有其他商标均为其各自所有者的财产。