C / C ++:检测多余的#包括?

我经常发现文件的标题部分一直变得越来越大,但是它永远不会变小。 在源文件的整个生命周期中,类可能已经被移动并被重构,并且很有可能有相当多的#includes不需要在那里。 将它们留在那里只会延长编译时间并增加不必要的编译依赖。 试图找出哪些仍然是需要的可能是非常乏味的。

是否有某种工具可以检测到多余的#include指令,并build议哪些可以安全删除?
皮棉可以做这个吗?

这不是自动的,但Doxygen会为#included文件生成依赖关系图。 你将不得不通过他们的视觉,但他们可以是非常有用的,以获得什么是使用什么的图片。

谷歌的cppclean(链接到: 下载 , 文档 )可以find几类C ++问题,现在可以find多余的#includes。

还有一个基于铿锵的工具, 包括你用什么 ,可以做到这一点。 包括你用什么,甚至可以build议前瞻性声明(所以你不必#include这么多),并select清理你的#包括你。

Eclipse CDT的当前版本也具有内置的这个function:在Source菜单下点击Organize Includes将按字母顺序排列你的#include,添加Eclipse认为你使用的任何标题而不直接包含它们,并且注释它所做的任何标题没想到你需要。 但是,此function不是100%可靠的。

另外检查包括你用什么 ,这解决了类似的问题。

检测多余的问题包括它不能只是一个types依赖检查器。 多余的包含文件对编译没有任何价值也不会改变其他文件依赖的其他项目。 头文件可以通过定义一个常量,重新定义和/或删除一个已经使用的macros,增加一个名字空间来改变一个名字的查找。 为了检测像命名空间这样的项目,你需要的不仅仅是预处理器,实际上你几乎需要一个完整的编译器。

林特是更多的风格检查,当然不会有这个完整的能力。

我想你会发现检测一个多余include的唯一方法是删除,编译和运行suite。

我以为PCLint会这样做,但是我已经看了几年了。 你可能会检查出来。

我看了一下这个博客 ,笔者谈了一些关于configurationPCLint来查找未使用的包含。 值得一看。

CScout重构浏览器可以检测C(不幸的是不是C ++)代码中多余的include指令。 你可以在这篇期刊文章中find它的工作原理。

您可以编写一个快速脚本来擦除单个#include指令,编译这些项目,并在没有编译错误发生时将#include中的名称和从中删除的文件logging下来。

让它在夜间运行,第二天你将有一个100%正确的包含文件的列表,你可以删除。

有时蛮力只是工作:-)


编辑:有时它不:-)。 这里有一些来自评论的信息:

  1. 有时候你可以单独去掉两个头文件,但是不能把它们放在一起。 一个解决scheme是在运行期间删除头文件,而不是把它们带回来。 这将find一个可以安全删除的文件列表,虽然可能有一个解决scheme,用更多的文件来删除这个algorithm不会find。 (这是对包含文件的删除空间的贪婪search,它只能find一个本地的最大值)
  2. 如果您根据某些#ifdefs的不同重新定义了一些macros,则行为可能会有细微的变化。 我认为这些是非常罕见的情况,作为构build的一部分的unit testing应该能够抓住这些变化。

对不起(重新)张贴在这里,人们往往不扩大评论。

检查我的评论crashmstr,FlexeLint / PC-Lint将为您做这个。 信息消息766.我的手册(版本8.0)的第11.8.1节讨论了这一点。

此外, 这很重要,不断迭代,直到消息消失 。 换句话说,在删除不用的头文件之后,重新运行lint,一旦删除了一些不需要的头文件,更多的头文件可能变得“不需要”了。 (这可能听起来很愚蠢,慢慢阅读并parsing它,这是有道理的。)

我从来没有find一个完整的工具来完成你所要求的。 我使用的最接近的东西是IncludeManager ,它可以标题包含树,这样你就可以直观地发现只包含在一个文件中的标题和循环头文件包含的内容。

如果您正在使用Eclipse CDT,则可以尝试http://includator.com ,该版本对testing版testing人员免费(在编写本文时),并自动删除多余的#includes或添加缺less的。 对于那些拥有FlexeLint或PC-Lint并且正在使用Elicpse CDT的用户, http: //linticator.com可能是一个选项(也可以免费进行betatesting)。 虽然它使用Lint的分析,但它提供了快速修复function,可以自动删除多余的#include语句。

我试过使用Flexelint(PC-Lint的unix版本),结果有些混杂。 这可能是因为我正在研究一个非常庞大而棘手的代码库。 我build议仔细检查每个报告为未使用的文件。

主要的担心是误报。 多个包含相同的头部报告为不需要的头部。 这是不好的,因为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书中一套精简的指南,可以最大限度地减less文件之间的物理依赖关系。 我已经使用了他们多年,我一直对结果感到非常满意。

  1. 每个cpp文件首先包含它自己的头文件。 [剪断]
  2. 一个头文件必须包含parsing它的所有头文件。 [剪断]
  3. 头文件应该有parsing它所需的最小数量的头文件。 [剪断]

这篇文章解释了#include通过使用Doxygenparsing的技术。 这只是一个perl脚本,所以它很容易使用。

有一个免费的工具包括文件依赖观察器 ,可以集成在Visual Studio中。 它显示多余的#包括红色。

也许有点晚,但我曾经find一个WebKit perl脚本,只是做你想要的。 它需要适应我相信(我不熟悉perl),但它应该做的伎俩:

http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes

(这是一个旧的分支,因为主干没有该文件了)

有两种types的多余的#include文件:

  1. 根本不需要模块(.c,.cpp)的头文件
  2. 头文件是由模块需要的,但不止一次,直接或间接包含。

根据我的经验,有两种方式可以很好地检测它:

  • gcc -H或cl.exe / showincludes(解决问题2)

    在现实世界中,如果所有Makefile都不覆盖CFLAGS选项,则可以在make之前导出CFLAGS = -H。 或者像我用的那样,你可以创build一个cc / g ++包装来强制地给每个$(CC)和$(CXX)调用添加-H选项。 并将包装目录前置到$ PATHvariables,那么你的make将全部使用你的包装命令。 当然你的包装应该调用真正的gcc编译器。 这个技巧需要改变,如果你的Makefile直接使用gcc。 而不是$(CC)或$(CXX)或隐含的规则。

    您也可以通过使用命令行进行调整来编译单个文件。 但是,如果你想清理整个项目的标题。 您可以通过以下方式捕获所有输出:

    使干净

    使2>&1 | tee result.txt

  • PC-Lint / FlexeLint(解决问题1和2)

    确保添加+ e766选项,这个警告是关于:未使用的头文件。

    pclint / flint -vf …

    这将导致pclint输出包含头文件,嵌套的头文件将被适当缩进。

为了结束这个讨论:c ++预处理器已经完成。 这是一个语义属性,包含是否是多余的。 因此,从莱斯定理得出,包含是否是多余的是不确定的。 不能有一个程序,(总是正确)检测包含是否是多余的。

这是一个简单的蛮力识别多余头包括的方式 。 这不是完美的,但消除了“明显”的不必要的包括。 摆脱这些在清理代码方面有很长的路要走。

脚本可以直接在GitHub上访问。

Gimpel Software公司的PC Lint可以报​​告什么时候一个包含文件被包含在一个编译单元中不止一次,但是它不能find你需要的包含文件。

编辑:它可以。 看到它的答案

JetBrains的C / C ++ IDE CLion检测冗余包括开箱即用。 这些在编辑器中是灰色的,但也有在当前文件或整个项目中优化包含的function。

我发现你付了这个function, 首次加载时,CLion需要一段时间来扫描和分析您的项目。