我经常发现文件的头部分总是变得越来越大,但它从来没有变小过。在源文件的整个生命周期中,类可能会被移动和重构,并且很可能有相当多的#include不需要存在。保留它们只会延长编译时间,并增加不必要的编译依赖关系。试图找出哪些仍然需要是相当乏味的。
是否有某种工具可以检测多余的#include指令,并建议哪些我可以安全地删除? 棉绒会这样吗?
我经常发现文件的头部分总是变得越来越大,但它从来没有变小过。在源文件的整个生命周期中,类可能会被移动和重构,并且很可能有相当多的#include不需要存在。保留它们只会延长编译时间,并增加不必要的编译依赖关系。试图找出哪些仍然需要是相当乏味的。
是否有某种工具可以检测多余的#include指令,并建议哪些我可以安全地删除? 棉绒会这样吗?
当前回答
我尝试过使用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文件首先包含它自己的头文件。(剪) 头文件必须包含解析它所需的所有头文件。(剪) 头文件应该有最少的头文件来解析它。(剪)
其他回答
有两种类型的多余的#include文件:
头文件实际上不需要 模块(.c, .cpp) 模块需要头文件 而是不止一次,直接或间接地。
根据我的经验,有两种方法可以很好地检测到它:
gcc -H or cl.exe /showincludes (resolve problem 2) In real world, you can export CFLAGS=-H before make, if all the Makefile's not override CFLAGS options. Or as I used, you can create a cc/g++ wrapper to add -H options forcibly to each invoke of $(CC) and $(CXX). and prepend the wrapper's directory to $PATH variable, then your make will all uses you wrapper command instead. Of course your wrapper should invoke the real gcc compiler. This tricks need to change if your Makefile uses gcc directly. instead of $(CC) or $(CXX) or by implied rules. You can also compile a single file by tweaking with the command line. But if you want to clean headers for the whole project. You can capture all the output by: make clean make 2>&1 | tee result.txt PC-Lint/FlexeLint(resolve problem both 1 and 2) make sure add the +e766 options, this warning is about: unused header files. pclint/flint -vf ... This will cause pclint output included header files, nested header files will be indented appropriately.
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的唯一方法是删除、编译和运行套件。
也许有点晚了,但我曾经找到一个WebKit perl脚本,它做的正是你想要的。我相信它需要一些调整(我不太精通perl),但它应该能做到:
http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes
(这是一个旧的分支,因为trunk不再有文件了)
CLion是JetBrains开发的C/ c++ IDE,可以即时检测冗余内容。这些在编辑器中是灰色的,但也有一些函数可以优化当前文件或整个项目中的包含。
我发现你需要为这个功能付费;当第一次加载时,CLion需要一段时间来扫描和分析您的项目。
您可以编写一个快速脚本,删除单个#include指令,编译项目,并在没有发生编译错误的情况下记录#include中的名称和它被删除的文件。
让它在晚上运行,第二天你就会有一个100%正确的可以删除的包含文件列表。
有时候蛮力很管用:-)
编辑:有时它不会:-)。下面是一些来自评论的信息:
Sometimes you can remove two header files separately, but not both together. A solution is to remove the header files during the run and not bring them back. This will find a list of files you can safely remove, although there might a solution with more files to remove which this algorithm won't find. (it's a greedy search over the space of include files to remove. It will only find a local maximum) There may be subtle changes in behavior if you have some macros redefined differently depending on some #ifdefs. I think these are very rare cases, and the Unit Tests which are part of the build should catch these changes.