首页 文章

在C / C中检测多余的#includes?

提问于
浏览
241

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

是否有某种工具可以检测多余的#include指令并建议哪些可以安全删除?
lint可能这样做吗?

19 回答

  • 0

    它不是自动的,但doxygen将为 #included 文件生成依赖关系图 . 你必须在视觉上仔细阅读它们,但它们对于获得正在使用什么的图片非常有用 .

  • 5

    谷歌的cppclean(链接到:downloaddocumentation)可以找到几类C问题,它现在可以找到多余的#includes .

    还有一个基于Clang的工具,include-what-you-use,可以做到这一点 . 包括你使用什么甚至可以建议前向声明(所以你没有#include这么多)并可选择为你清理你的#includes .

    当前版本的Eclipse CDT也具有内置的此功能:进入“源”菜单,然后单击“组织包含”将使用#include 's, add any headers that Eclipse thinks you'使用而不直接包含它们,并注释掉它不具有100%可靠性的任何 Headers .

  • 23

    还可以查看include-what-you-use,它解决了类似的问题 .

  • 2

    检测多余包含的问题在于它不能仅仅是类型依赖性检查器 . 多余的include是一个文件,它不会为编译提供任何有 Value 的东西 and 不会改变其他文件所依赖的另一个项目 . 头文件可以通过多种方式改变编译,例如通过定义常量,重新定义和/或删除已使用的宏,添加一个命名空间,该命名空间可以在某种程度上改变名称的查找 . 为了检测命名空间之类的项目,您需要的不仅仅是预处理器,实际上您几乎需要一个完整的编译器 .

    Lint更像是一种风格检查器,当然不具备这种全部功能 .

    我想你会发现检测多余包含的唯一方法是删除,编译和运行套件 .

  • 39

    我认为PCLint会做到这一点,但是我已经看了几年了 . 你可以看一下 .

    我查看了this blog并且作者谈了一些关于配置PCLint以查找未使用的包含的内容 . 也许值得一瞧 .

  • 54

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

  • 0

    您可以编写一个快速脚本来擦除单个#include指令,编译项目,并在没有编译错误的情况下将名称记录在#include中,并将其从中删除 .

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

    有时蛮力只是起作用:-)


    edit: 有时它不会从评论中得到一些信息:

    • 有时您可以单独删除两个头文件,但不能同时删除两个头文件 . 解决方案是在运行期间删除头文件而不是将它们带回来 . 这将找到一个可以安全删除的文件列表,尽管可能有一个解决方案需要删除更多文件,这个算法赢得了对要删除的包含文件空间的贪婪搜索 . 它只会找到一个本地最大值)

    • 如果您根据某些#ifdef重新定义了一些宏,则行为可能会有细微的变化 . 我认为这些是非常罕见的情况,作为构建的一部分的单元测试应该捕获这些变化 .

  • 7

    抱歉(重新)发布在这里,人们通常不会扩展评论 .

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

    另外, and this is important, keep iterating until the message goes away . 换句话说,在删除未使用的标头后,重新运行lint,一旦删除一些不需要的标头,更多的头文件可能会变成"unneeded" . (这可能听起来很傻,慢慢阅读并解析它,这很有道理 . )

  • 1

    我问了.1333981 . 我用过的最接近的是IncludeManager,其中绘制您的 Headers 包含树,以便您可以直观地发现仅包含在一个文件和圆形 Headers 内容中的 Headers .

  • 5

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

  • 1

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

    主要担心是误报 . 将包含相同标头的多个包含报告为不需要的标头 . 这很糟糕,因为Flexelint没有告诉您 Headers 包含在哪个行或之前包含的位置 .

    自动化工具可以解决这个问题的方法之一:

    在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依赖 . 有更多的病理情况,但基本上你需要自己检查 Headers 以获得最佳效果 .

    我强烈推荐这篇文章来自内部的博客Physical Structure and C++ . 他们建议采用全面的方法清理#include混乱:

    指南这是Lakos的书中一套精心设计的指南,它可以最大限度地减少文件之间的物理依赖关系 . 我已经使用它们多年了,我一直对结果非常满意 . 每个cpp文件首先包含自己的头文件 . [snip]头文件必须包含解析它所需的所有头文件 . [snip]头文件应该具有解析它所需的最少数量的头文件 . [剪断]

  • 142

    This article解释了使用Doxygen解析#include删除的技巧 . 那个's just a perl script, so it'很容易使用 .

  • 2

    有一个免费工具Include File Dependencies Watcher可以集成在visual studio中 . 它以红色显示多余的#includes .

  • 2

    结束这个讨论:c预处理器是完整的 . 这是一个语义属性,包含是否是多余的 . 因此,从莱斯定理得出,包含是否是多余的是不可判定的 . 不能有一个程序,(总是正确地)检测包含是否是多余的 .

  • 2

    也许有点晚了,但我曾经发现一个WebKit perl脚本可以完成你想要的 . 它需要一些适应我相信(我不熟悉perl),但它应该做的伎俩:

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

    (这是一个旧分支,因为trunk不再有文件)

  • 5

    有两种类型的多余#include文件:

    • 模块(.c,.cpp)实际上根本不需要头文件

    • 模块需要头文件,但不止一次,直接或间接包含头文件 .

    我的经验有两种方法可以很好地检测它:

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

    在现实世界中,如果所有Makefile都不覆盖CFLAGS选项,则可以在make之前导出CFLAGS = -H . 或者就像我使用的那样,你可以创建一个cc / g包装器来强制向$(CC)和$(CXX)的每个调用添加-H选项 . 并将包装器的目录添加到$ PATH变量,然后你的make将全部使用你的包装器命令 . 当然你的包装器应该调用真正的gcc编译器 . 如果您的Makefile直接使用gcc,则需要更改此技巧 . 代替$(CC)或$(CXX)或隐含规则 .

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

    干净

    make 2>&1 | tee result.txt

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

    确保添加e766选项,此警告是关于:未使用的头文件 .

    pclint / flint -vf ...

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

  • 1

    这是一个简单的brute force way of identifying superfluous header includes . 它并不完美但却消除了"obvious"不必要的包含 . 摆脱这些在清理代码方面有很长的路要走 .

    scripts可以直接在GitHub上访问 .

  • 4

    Gimpel Software的PC Lint可以报告包含文件的时间在编译单元中包含多次,但它找不到您要查找的方式所不需要的包含文件 .

    Edit: 它可以 . 见itsmatt's answer

  • 15

    CLion,JetBrains的C / C IDE,检测冗余包括开箱即用 . 这些在编辑器中显示为灰色,但也有optimise includes in the current file or whole project的功能 .

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

相关问题