如何处理 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. 的商标。所有其他商标均为其各自所有者的财产。