
How should I detect unnecessary #include files in a large C++ project?
我正在Visual Studio 2008中从事大型C ++项目,并且有很多文件带有不必要的
虽然它不会显示不需要的包含文件,但Visual Studio具有设置 您还可以看一下pimpl习惯用法,以减少对头文件的依赖,从而更轻松地查看可以删除的内容。 PC Lint对此非常有效,它也为您找到了其他各种愚蠢的问题。它具有可用于在Visual Studio中创建外部工具的命令行选项,但我发现Visual Lint加载项更易于使用。甚至Visual Lint的免费版本也有帮助。但是,试试PC-Lint。配置它使其不会给您太多警告会花费一些时间,但是您会惊讶于它的出现。 有一个新的基于Clang的工具,包括您所使用的工具,旨在实现此目的。 免责声明!我使用的是商用静态分析工具(不是PC Lint)。免责声明! 简单的非解析方法存在几个问题: 1)过载设置: 重载函数可能具有来自不同文件的声明。删除一个头文件可能导致选择了不同的重载,而不是编译错误!结果将是语义上的无声更改,此后可能很难跟踪。 2)模板专长: 与重载示例类似,如果您对模板有部分或明确的专长,则希望在使用模板时将它们全部可见。主模板的专门化可能在不同的头文件中。删除带有特殊化的标题不会导致编译错误,但是如果选择了该特殊化,则可能导致不确定的行为。 (请参阅:C ++函数模板专业化的可见性) 正如" msalters"指出的那样,对代码执行完整的分析还可以分析类的用法。通过检查如何通过特定的文件路径使用类,可以完全删除该类的定义(以及所有其相关性),或者至少将其移到更接近include中主要源的级别。树。 我不知道有任何这样的工具,并且我曾经考虑过编写一个工具,但是事实证明,这是一个很难解决的问题。
假设您的源文件包含a.h和b.h; a.h包含 无论使用哪种工具,都需要知道您的构建环境。如果a.h看起来像:
然后,只有在定义了 像Timmermans一样,我对任何工具都不熟悉。但是我知道有一些程序员编写了Perl(或Python)脚本,试图一次注释掉每个包含行,然后编译每个文件。 看来现在Eric Raymond拥有用于此的工具。 Google的cpplint.py有一个"包含您使用的内容"规则(还有许多其他规则),但据我所知,没有"仅包含您使用的内容"规则。即使这样,它还是有用的。 一般而言,如果您对此主题感兴趣,则可以查看Lakos的大规模C ++软件设计。这有些陈旧,但是会遇到很多"物理设计"问题,例如找到需要包含的标头的绝对最小值。我还没有真正在其他地方看到过这种讨论。 您可以使用C / C ++ Include File Dependencies Watcher构建一个包含图,并在视觉上找到不需要的包含。
尝试包括管理器。它可以轻松集成到Visual Studio中,并可视化您的包含路径,这有助于您查找不必要的内容。 如果您的头文件通常以
(而不是一次使用#pragma),您可以将其更改为:
而且由于编译器会输出正在编译的cpp文件的名称,因此至少可以让您知道哪个cpp文件导致多次引入标头。 PC-Lint确实可以做到这一点。一种简单的方法是将其配置为仅检测未使用的包含文件并忽略所有其他问题。这非常简单-仅启用消息766("模块中未使用头文件"),只需在命令行中包含选项-w0 + e766。 相同的方法也可以用于相关消息,例如964("模块中不直接使用头文件")和966("模块中不直接使用间接包含的头文件")。 我在上周的博客文章http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318中更详细地介绍了FWIW。
如果您要删除不必要的
当然,如果您已经有一个并行的构建过程,并且仍在尝试加快它的速度,那么一定要清理您的 从每个包含文件开始,并确保每个包含文件仅包含编译自身所需的内容。然后,C ++文件缺少的所有包含文件都可以添加到C ++文件本身。 对于每个包含文件和源文件,一次注释掉每个包含文件,然后查看其是否可以编译。 将包含文件按字母顺序排序也是一个好主意,如果不可能,请添加注释。 最新的Jetbrains IDE CLion自动显示(灰色)当前文件中未使用的包含项。 也可以从IDE中获取所有未使用的包含项(以及函数,方法等)的列表。
添加以下一个或两个#defines
请参阅http://support.microsoft.com/kb/166474 如果您要使用Eclipse CDT,则可以尝试http://includator.com来优化您的包含结构。但是,Includator可能对VC ++的预定义包含并不足够了解,并且CDT尚未内置CDT以将VC ++与正确的包含一起使用。 如果尚未使用,则使用预编译的头文件包含所有您不会更改的内容(平台头文件,外部SDK头文件或项目的静态已完成部分)将在构建时间上产生巨大差异。 http://msdn.microsoft.com/zh-CN/library/szfdksca(VS.71).aspx 另外,尽管对您的项目来说可能为时已晚,但将项目组织成多个部分,并且不将所有本地标头集中到一个大的主标头中,是一个好习惯,尽管这需要一些额外的工作。 现有的一些答案表明这很困难。的确如此,因为您需要一个完整的编译器来检测前向声明是适当的情况。您无法在不了解符号含义的情况下解析C ++。语法太含糊了。您必须知道某个名称是命名一个类(可以被向前声明)还是一个变量(不能)。另外,您需要了解名称空间。 也许有点晚了,但是我曾经发现一个WebKit perl脚本可以完成您想要的操作。我相信它需要一些调整(我不太熟悉perl),但是应该可以解决问题: http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes (这是一个旧的分支,因为中继不再具有该文件)
如果有一个您认为不再需要的特定标头(例如,
当然,您的接口标头可能会使用其他#define约定 然后重建。有三种可能性:
请注意,取决于.h或.c直接使用时的间接包含
其他答案中有关修改行为的标头的注意事项 |