标头包含优化

时间:2009-12-08 19:59:21

标签: c++

是否有一种自动方法可以优化C ++中头文件的包含,从而提高编译时间? “自动”一词是指工具或程序。是否有可能找到哪些头文件已过时(例如,未使用暴露的功能)?

编辑:让每个包含标题“仅包含一次”是一件重要的事情,但是有一种方法甚至可以更改文件的内容,以便经常使用的“功能”具体包括在内经常使用的功能是在其他包括?我问的太多了?不幸的是,我们正在讨论一个包含数千个文件的现有代码库。它可能是我实际要求的重构工具吗?

谢谢。

10 个答案:

答案 0 :(得分:18)

更新

我认为你真正想要的是“包括你使用的东西”,而不是一组最小的标题。 IWYU意味着尽可能向前声明,并包含直接声明您使用的符号的标头。你不能盲目地将文件转换为IWYU,因为它可能不再编译。发生这种情况时,您需要找到丢失的标题并添加它。但是,如果每个文件都是IWYU,那么即使您必须偶尔添加标题,您的编译也将是faster overall。更不用说你的标题会更多meaningful/self-documenting

正如我之前的回答所指出的那样,技术上可以包含比IWYU更少的标题,但这通常是浪费时间。

现在,如果只有大多数IWYU为您重构grunt工作的工具:)


我曾经考虑过创建/使用这样的工具一次。我们的想法是使用二进制搜索和重复编译来查找最小的包含集。经过进一步调查,它似乎没有用处。

一些问题:

  • 更改包含的头文件可以更改行为,仍然允许编译文件。特别是一个例子,如果您在单独的头文件中定义了自己的std::swap。您可以删除该标头,您的代码仍将使用默认的std::swap实现进行编译。但是,std::swap可能是:低效,导致运行时错误,或者更糟糕的是产生错误的逻辑错误。

  • 有时,头文件包含作为文档。例如,要使用std::foreach,通常包括<vector>就足以让它进行编译。使用额外的#include <algorithm>

  • ,代码更有意义
  • 编译器或编译器版本之间的最小编译集可能不可移植。再次使用std::foreach示例,无法保证std::foreach将提供<vector>

  • 最小的包含集合可能不会显着影响编译时间。 Visual Studio和gcc支持#pragma once,它们重复包含了基本上不存在的性能。并且至少gcc的预处理器已经过优化,可以非常快速地处理包括警卫(尽快#pragma once)。

答案 1 :(得分:5)

大多数编译器都对预编译的头文件有某种支持。

删除完全不需要的包含的工具可能不错。您似乎暗示您希望看到一个删除所需包含的内容被其他包含的内容冗余。我不会成为狂热的粉丝。有人可能会删除另一个冗余包括一天,然后其他一些可怜的懒人将不得不追踪硬盘上某处包含文件的所有缺失符号突然出现在他们身上。

答案 2 :(得分:4)

PC-Lint将报告未使用的包含文件。

答案 3 :(得分:1)

GCC在precompiled headers这个主题上有一些工作,但是有一些限制(如果我记得的话,每个编译只能包含一个预编译的头文件。)

如果您不使用GCC,此解决方案将无法帮助您,因为它不会生成可供其他编译器使用的简化标头。

答案 4 :(得分:1)

GamesFromWithin博客上有一篇关于C ++标题的好文章,甚至还有一个工具列出了最多包含哪些标题(因此也是pimpl / pch / forwarding的主要候选者)。好的工具,虽然在perl中,我实际上用了几次来挖掘一些好的数据,当构建时间让我(太多)疯了。

答案 5 :(得分:0)

我从来没有听说过任何工具跟踪无用的包含。这只是一件小事。

但是,无论如何你应该注意它。如何组织标题和实现取决于您如何组织代码。将您的项目视为独立部分非常重要,标题将部分强制您考虑它。

答案 6 :(得分:0)

我曾经写过一个简单的工具来做这件事,它工作得非常好,尽管是以最可怕的蛮力方式。

它递归了项目中的所有h / cpp文件 对于每个人,它搜索#includes,并依次在每个人面前添加//,然后触发构建。如果构建返回错误,则取消//。如果构建成功,则会将include行注释掉。

处理所有cpp文件非常快(一个小时左右),但我必须让它在整个周末都在代码库上运行以处理标题,但它实现起来非常简单并且非常有效。它只需要每年运行一次,以清除积累的绒毛。

它产生了一个小的但显着的差异(在70分钟的建筑IIRC上大约5分钟)。

答案 7 :(得分:0)

我最近找到了一个可以完全按照你要求做的工具。

在Ben Ziegler的博客Double Buffered上,他发布了一些build system optimizations

  

所以,我提出了复杂的   Brute Force Perl脚本的解决方案。   基本上,我会扫描所有   我们的代码和尝试中的.c文件   注释掉每个#include   指示。然后它会重新编译   代码库,看看是否有   错误。如果有它会恢复   评论然后再继续   下一个。

结果不是很好。没有明显的构建时间改进。

我仍然支持first answer;这是浪费时间,不明智。

这里的任何一种方式都是他的perl script。你需要对它进行一些破解才能使它能够处理你的代码,但核心应该可以正常工作。

答案 8 :(得分:0)

Google的cppclean将帮助您删除不必要的头文件。它会产生一些误报,但它提供了一个很好的起点。请参阅我对类似问题和评论的回答here

答案 9 :(得分:-5)

预编译的标头很糟糕。

这实际上是一个链接器问题,除了获得更好的链接器(祝你好运)或者以一种在链接器上更容易的方式编写代码之外,它没有任何关系。