我经常发现文件的头部分总是变得越来越大,但它从来没有变小过。在源文件的整个生命周期中,类可能会被移动和重构,并且很可能有相当多的#include不需要存在。保留它们只会延长编译时间,并增加不必要的编译依赖关系。试图找出哪些仍然需要是相当乏味的。
是否有某种工具可以检测多余的#include指令,并建议哪些我可以安全地删除? 棉绒会这样吗?
我经常发现文件的头部分总是变得越来越大,但它从来没有变小过。在源文件的整个生命周期中,类可能会被移动和重构,并且很可能有相当多的#include不需要存在。保留它们只会延长编译时间,并增加不必要的编译依赖关系。试图找出哪些仍然需要是相当乏味的。
是否有某种工具可以检测多余的#include指令,并建议哪些我可以安全地删除? 棉绒会这样吗?
当前回答
很抱歉(再次)在这里发帖,人们通常不扩展评论。
检查我对crashmstr的评论,FlexeLint / PC-Lint会为你做这件事。信息信息766号。我的手册(8.0版)的11.8.1节讨论了这个问题。
另外,这一点很重要,不断迭代,直到消息消失。换句话说,在删除了不需要的头文件后,重新运行lint,一旦删除了一些不需要的头文件,更多的头文件可能已经成为“不需要的”。(这可能听起来很傻,慢慢读并分析它,这是有道理的。)
其他回答
我尝试过使用Flexelint (PC-Lint的unix版本),结果有些复杂。这可能是因为我正在处理一个非常庞大且复杂的代码库。我建议仔细检查报告为未使用的每个文件。
主要的担忧是假阳性。同一报头的多个包含被报告为不需要的报头。这是很糟糕的,因为Flexelint没有告诉你头文件被包含在哪一行或者它之前被包含在哪里。
自动化工具可能会出错的一种方式是:
在A.hpp:
class A {
// ...
};
在B.hpp:
#include "A.hpp
class B {
public:
A foo;
};
在C.cpp:
#include "C.hpp"
#include "B.hpp" // <-- Unneeded, but lint reports it as needed
#include "A.hpp" // <-- Needed, but lint reports it as unneeded
如果你盲目地跟随Flexelint的消息,你会把#include依赖项搞砸。有更多的病理情况,但基本上你需要自己检查标题,以获得最好的结果。
我强烈推荐这篇来自博客Games的关于物理结构和c++的文章。他们推荐了一个全面的方法来清理#include混乱:
的指导方针 以下是从Lakos的书中提炼出来的一组指导原则,可以最大限度地减少文件之间的物理依赖关系。我已经使用它们很多年了,我对效果一直很满意。 每个cpp文件首先包含它自己的头文件。(剪) 头文件必须包含解析它所需的所有头文件。(剪) 头文件应该有最少的头文件来解析它。(剪)
谷歌的cppclean(链接到:下载,文档)可以找到几种类型的c++问题,现在它可以找到多余的#includes。
还有一个基于clang的工具(包括您所使用的工具)可以做到这一点。include-what-you-use甚至可以建议前向声明(因此您不必#include那么多),并可选地为您清理#includes。
当前版本的Eclipse CDT也内置了这个功能:在Source菜单下单击Organize Includes将按字母顺序排列#include,添加Eclipse认为您正在使用的任何标题,但不直接包括它们,并注释掉它认为您不需要的任何标题。然而,这个特性并不是100%可靠。
CLion是JetBrains开发的C/ c++ IDE,可以即时检测冗余内容。这些在编辑器中是灰色的,但也有一些函数可以优化当前文件或整个项目中的包含。
我发现你需要为这个功能付费;当第一次加载时,CLion需要一段时间来扫描和分析您的项目。
The problem with detecting superfluous includes is that it can't be just a type dependency checker. A superfluous include is a file which provides nothing of value to the compilation and does not alter another item which other files depend. There are many ways a header file can alter a compile, say by defining a constant, redefining and/or deleting a used macro, adding a namespace which alters the lookup of a name some way down the line. In order to detect items like the namespace you need much more than a preprocessor, you in fact almost need a full compiler.
Lint更多的是一个样式检查器,当然不会有这个完整的功能。
我想你会发现检测多余include的唯一方法是删除、编译和运行套件。
我从来没有找到一个成熟的工具来完成你的要求。我使用过的最接近的工具是IncludeManager,它将头包含树图形化,以便您可以直观地发现只包含在一个文件中的头和循环头包含之类的内容。