我经常发现文件的标头部分一直都在变大,但从未变小。在源文件的整个生命周期中,类可能已经移动并被重构,并且很可能有很多#includes
不需要再存在了。将它们保留在那里只会延长编译时间,并增加不必要的编译依赖项。试图弄清仍然需要哪些可能会很乏味。
是否有某种工具可以检测到多余的#include指令并建议可以安全删除的指令?
皮棉可以这样做吗?
我经常发现文件的标头部分一直都在变大,但从未变小。在源文件的整个生命周期中,类可能已经移动并被重构,并且很可能有很多#includes
不需要再存在了。将它们保留在那里只会延长编译时间,并增加不必要的编译依赖项。试图弄清仍然需要哪些可能会很乏味。
是否有某种工具可以检测到多余的#include指令并建议可以安全删除的指令?
皮棉可以这样做吗?
Answers:
它不是自动的,但是doxygen会生成#included
文件的依赖关系图。您将不得不在视觉上浏览它们,但是它们对于获取正在使用什么的图片非常有用。
Google的cppclean(链接到下载,文档)可以找到几类C ++问题,并且现在可以找到多余的#include。
还有一个基于Clang的工具,包括“使用什么”,可以做到这一点。include-what-you-use甚至可以建议使用前向声明(因此您不必#include太多),还可以选择为您清理#includes。
当前版本的Eclipse CDT也内置了此功能:在“源”菜单下,单击“组织包含”将按字母顺序排列您的#include,添加Eclipse认为您正在使用的所有标头而不直接包含它们,并注释掉它没有的任何标头认为您不需要。但是,此功能并非100%可靠。
还请检查include-what-you-use,它可以解决类似的问题。
检测多余的include的问题在于它不能仅仅是类型依赖项检查器。多余的包含是一个文件,该文件对编译没有任何价值,并且不会更改其他文件依赖的另一个项目。头文件可以通过多种方式更改编译,例如,通过定义常量,重新定义和/或删除已使用的宏,添加名称空间以某种方式更改名称的查找。为了检测诸如名称空间之类的项目,您需要的不仅仅是预处理器,实际上,您几乎需要完整的编译器。
Lint更像是一个样式检查器,当然不会具有这种全部功能。
我认为您会发现检测多余的包含的唯一方法是删除,编译和运行套件。
您可以编写一个快速脚本,以擦除单个#include指令,编译项目,然后在未发生编译错误的情况下,将名称记录在#include中以及从中删除的文件中。
让它在夜间运行,第二天,您将可以100%正确地删除包含文件。
有时蛮力就可以了:-)
编辑:有时它不是:-)。以下是评论中的一些信息:
很抱歉在这里(重新)发布信息,人们通常不会扩展评论。
检查我对crashmstr的评论,FlexeLint / PC-Lint将为您完成此操作。信息性消息766。我的手册(8.0版)的11.8.1节对此进行了讨论。
另外,这很重要,请不断迭代直到消息消失。换句话说,在删除未使用的头文件后,重新运行lint,一旦删除了一些不需要的头文件,更多的头文件可能变得“不需要”。(这听起来很傻,慢慢阅读并解析它,这是有道理的。)
我从未找到能够满足您要求的功能完善的工具。我使用过的最接近的是IncludeManager,它绘制了标头包含树的图形,因此您可以直观地发现诸如仅包含在一个文件中的标头和圆形标头包含在内的内容。
我尝试使用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依赖项。还有更多的病理情况,但基本上,您将需要自己检查标题以获取最佳结果。
我强烈建议您从内部博客游戏中发表有关物理结构和C ++的文章。他们建议采用一种综合方法来清理#include混乱:
指导方针
这是Lakos的书中提炼的一套指导,可最大程度地减少文件之间的物理依赖性。我使用它们已有多年了,我一直对结果非常满意。
- 每个cpp文件首先包含其自己的头文件。[片段]
- 头文件必须包含解析它所必需的所有头文件。[片段]
- 头文件应该具有解析它所必需的头文件的最少数量。[片段]
如果您使用的是Eclipse CDT,则可以尝试http://includator.com,它对于Beta测试人员是免费的(在撰写本文时),并且会自动删除多余的#include或添加缺失的#include。对于拥有FlexeLint或PC-Lint并使用Elicpse CDT的用户,可以选择http://linticator.com(对于Beta测试也是免费的)。当使用Lint的分析时,它提供了快速修复程序,可自动删除多余的#include语句。
也许有点晚了,但是我曾经发现一个WebKit perl脚本可以完成您想要的操作。我相信它需要一些调整(我不太了解perl),但是应该可以解决问题:
(这是一个旧的分支,因为中继不再具有该文件)
有一个免费工具Include File Dependencies Watcher,可以集成到Visual Studio中。它以红色显示多余的#includes。
多余的#include文件有两种类型:
根据我的经验,有两种方法可以很好地检测到它:
gcc -H或cl.exe / showincludes(解决问题2)
在现实世界中,如果所有Makefile都未覆盖CFLAGS选项,则可以在make之前导出CFLAGS = -H。或者像我以前使用的那样,您可以创建一个cc / g ++包装器,将-H选项强行添加到$(CC)和$(CXX)的每次调用中。并将包装器的目录放在$ PATH变量之前,那么make将全部使用您的包装器命令。当然,您的包装器应该调用真正的gcc编译器。如果您的Makefile直接使用gcc,则需要更改此技巧。而不是$(CC)或$(CXX)或隐含规则。
您还可以通过使用命令行进行调整来编译单个文件。但是,如果您要清理整个项目的标题。您可以通过以下方式捕获所有输出:
弄干净
使2>&1 | 发球result.txt
PC-Lint / FlexeLint(解决问题1和2)
确保添加+ e766选项,此警告是关于:未使用的头文件。
pclint / flint -vf ...
这将导致pclint输出包含的头文件,嵌套的头文件将适当缩进。
结束本讨论:c ++预处理器即将完成。无论include是否是多余的,这都是语义属性。因此,根据赖斯定理,不确定包含是否是多余的是不确定的。不可能有一个程序(总是正确地)检测包含是否多余。
来自JetBrains的C / C ++ IDE CLion检测开箱即用的冗余组件。这些在编辑器中显示为灰色,但是还有一些函数可以优化当前文件或整个项目中的包含。
我发现您需要为此功能付费;首次加载时,CLion需要一段时间来扫描和分析您的项目。