如何检测大型c++项目中不必要的#include文件?

时间:2022-04-02 11:04:06

I am working on a large C++ project in Visual Studio 2008, and there are a lot of files with unnecessary #include directives. Sometimes the #includes are just artifacts and everything will compile fine with them removed, and in other cases classes could be forward declared and the #include could be moved to the .cpp file. Are there any good tools for detecting both of these cases?

在Visual Studio 2008中,我正在开发一个大型c++项目,有很多文件都没有必要的#include指令。有时,#include仅仅是工件,所有东西都可以通过删除它们进行编译,在其他情况下,类可以向前声明,#include可以移动到.cpp文件。有没有好的工具来检测这两种情况?

20 个解决方案

#1


45  

While it won't reveal unneeded include files, Visual studio has a setting /showIncludes (right click on a .cpp file, Properties->C/C++->Advanced) that will output a tree of all included files at compile time. This can help in identifying files that shouldn't need to be included.

虽然它不会显示不需要的文件,但是Visual studio有一个设置/ showinclude(右击一个.cpp文件,属性->C/ c++ ->Advanced),它将在编译时输出所有包含文件的树。这有助于识别不需要包含的文件。

You can also take a look at the pimpl idiom to let you get away with fewer header file dependencies to make it easier to see the cruft that you can remove.

您还可以查看pimpl习惯用法,以减少头文件依赖,以便更容易看到可以删除的cruft。

#2


28  

PC Lint works quite well for this, and it finds all sorts of other goofy problems for you too. It has command line options that can be used to create External Tools in Visual Studio, but I've found that the Visual Lint addin is easier to work with. Even the free version of Visual Lint helps. But give PC-Lint a shot. Configuring it so it doesn't give you too many warnings takes a bit of time, but you'll be amazed at what it turns up.

PC Lint在这方面工作得很好,它还为您发现了其他各种各样的问题。它有命令行选项,可以用来在Visual Studio中创建外部工具,但是我发现Visual Lint addin更容易使用。甚至免费版的Visual Lint也有帮助。但是给PC-Lint一个机会。配置它以使它不会给您带来太多的警告需要一些时间,但是您会对它的出现感到惊讶。

#3


26  

There's a new Clang-based tool, include-what-you-use, that aims to do this.

有一种新的基于铿锵的工具,包括“你用什么”,旨在实现这一点。

#4


25  

!!DISCLAIMER!! I work on a commercial static analysis tool (not PC Lint). !!DISCLAIMER!!

! !免责声明! !我从事商业静态分析工具(不是PC Lint)。! !免责声明! !

There are several issues with a simple non parsing approach:

使用简单的非解析方法有几个问题:

1) Overload Sets:

1)过载集:

It's possible that an overloaded function has declarations that come from different files. It might be that removing one header file results in a different overload being chosen rather than a compile error! The result will be a silent change in semantics that may be very difficult to track down afterwards.

重载函数可能有来自不同文件的声明。删除一个头文件可能会导致选择不同的重载,而不是编译错误!结果将是语义上的一种无声的变化,在之后可能很难找到。

2) Template specializations:

2)模板专门化:

Similar to the overload example, if you have partial or explicit specializations for a template you want them all to be visible when the template is used. It might be that specializations for the primary template are in different header files. Removing the header with the specialization will not cause a compile error, but may result in undefined behaviour if that specialization would have been selected. (See: Visibility of template specialization of C++ function)

与重载示例类似,如果您对模板有部分或显式的专门化,那么在使用模板时,您希望它们都是可见的。主要模板的专门化可能在不同的头文件中。使用专门化删除标头不会导致编译错误,但如果选择了专门化,则可能导致未定义的行为。(参见:c++函数模板专门化的可见性)

As pointed out by 'msalters', performing a full analysis of the code also allows for analysis of class usage. By checking how a class is used though a specific path of files, it is possible that the definition of the class (and therefore all of its dependnecies) can be removed completely or at least moved to a level closer to the main source in the include tree.

正如“msalters”所指出的,对代码执行完整的分析也允许分析类的使用。通过检查一个类如何使用特定的文件路径,可能会完全删除类的定义(因此所有的依赖项),或者至少移动到更接近包含树中的主源的级别。

#5


10  

I don't know of any such tools, and I have thought about writing one in the past, but it turns out that this is a difficult problem to solve.

我不知道有任何这样的工具,我以前也想过写一个,但结果证明这是一个很难解决的问题。

Say your source file includes a.h and b.h; a.h contains #define USE_FEATURE_X and b.h uses #ifdef USE_FEATURE_X. If #include "a.h" is commented out, your file may still compile, but may not do what you expect. Detecting this programatically is non-trivial.

说你的源文件包含一个。h和b.h;一个。h包含#define USE_FEATURE_X和b。使用# ifdef USE_FEATURE_X h。如果# include "。h"被注释掉了,你的文件可能仍然被编译,但是可能不会做你所期望的。以编程的方式检测它是非常重要的。

Whatever tool does this would need to know your build environment as well. If a.h looks like:

无论使用什么工具,都需要了解您的构建环境。如果一个。h的样子:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

Then USE_FEATURE_X is only defined if WINNT is defined, so the tool would need to know what directives are generated by the compiler itself as well as which ones are specified in the compile command rather than in a header file.

然后USE_FEATURE_X只在定义WINNT时才被定义,因此工具需要知道编译器本身生成什么指令,以及在编译命令中指定哪些指令,而不是在头文件中。

#6


9  

Like Timmermans, I'm not familiar with any tools for this. But I have known programmers who wrote a Perl (or Python) script to try commenting out each include line one at a time and then compile each file.

和Timmermans一样,我对任何工具都不熟悉。但是我认识一些程序员,他们编写了一个Perl(或Python)脚本,尝试一次注释掉每个包含第一行,然后编译每个文件。


It appears that now Eric Raymond has a tool for this.

看来Eric Raymond已经有了一个工具。

Google's cpplint.py has an "include what you use" rule (among many others), but as far as I can tell, no "include only what you use." Even so, it can be useful.

谷歌的cpplint。py有一个“包含您使用的内容”规则(包括许多其他规则),但是据我所知,no“只包含您使用的内容”。即便如此,它还是有用的。

#7


5  

If you're interested in this topic in general, you might want to check out Lakos' Large Scale C++ Software Design. It's a bit dated, but goes into lots of "physical design" issues like finding the absolute minimum of headers that need to be included. I haven't really seen this sort of thing discussed anywhere else.

如果您对这个主题感兴趣,您可能想看看Lakos的大型c++软件设计。它有点过时,但涉及到很多“物理设计”问题,比如找到需要包含的标题的绝对最小值。我还没见过其他地方讨论过的东西。

#8


4  

If your header files generally start with

如果你的头文件通常以开头

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif

(as opposed to using #pragma once) you could change that to:

(与一次性使用#pragma不同)您可以将其更改为:

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else 
#pragma message("Someheader.h superfluously included")
#endif

And since the compiler outputs the name of the cpp file being compiled, that would let you know at least which cpp file is causing the header to be brought in multiple times.

由于编译器输出正在编译的cpp文件的名称,这至少可以让您知道哪个cpp文件导致头文件被多次引入。

#9


4  

Give Include Manager a try. It integrates easily in Visual Studio and visualizes your include paths which helps you to find unnecessary stuff. Internally it uses Graphviz but there are many more cool features. And although it is a commercial product it has a very low price.

给予包括经理一个尝试。它很容易在Visual Studio中集成,并可视化您的包含路径,帮助您找到不必要的东西。在内部,它使用Graphviz,但还有许多更酷的特性。虽然它是一种商业产品,但价格很低。

#10


4  

You can build an include graph using C/C++ Include File Dependencies Watcher, and find unneeded includes visually.

您可以使用C/ c++构建一个包含文件依赖的监视器,并且在视觉上发现不需要的内容。

#11


3  

PC-Lint can indeed do this. One easy way to do this is to configure it to detect just unused include files and ignore all other issues. This is pretty straightforward - to enable just message 766 ("Header file not used in module"), just include the options -w0 +e766 on the command line.

PC-Lint确实可以做到这一点。一种简单的方法是将它配置为仅检测未使用的include文件并忽略所有其他问题。这非常简单—要启用消息766(“在模块中不使用头文件”),只需在命令行中包含选项-w0 +e766。

The same approach can also be used with related messages such as 964 ("Header file not directly used in module") and 966 ("Indirectly included header file not used in module").

同样的方法也可以用于相关的消息,如964(“不直接在模块中使用头文件”)和966(“间接包括模块中不使用的头文件”)。

FWIW I wrote about this in more detail in a blog post last week at http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318.

FWIW我上周在http://www.riverblade.co.uk/blog.php?archive= 2008_09_091_archive.xml #3575027665614976318的一篇博客文章中更详细地描述了这一点。

#12


2  

If you are looking to remove unnecessary #include files in order to decrease build times, your time and money might be better spent parallelizing your build process using cl.exe /MP, make -j, Xoreax IncrediBuild, distcc/icecream, etc.

如果您希望删除不必要的#include文件以减少构建时间,您的时间和金钱最好使用cl并行化构建过程。exe /MP, make -j, Xoreax置信构建,distcc/icecream等。

Of course, if you already have a parallel build process and you're still trying to speed it up, then by all means clean up your #include directives and remove those unnecessary dependencies.

当然,如果您已经有一个并行的构建过程,并且您还在试图加快它的速度,那么通过所有的方法清除您的#include指令并删除那些不必要的依赖项。

#13


2  

Start with each include file, and ensure that each include file only includes what is necessary to compile itself. Any include files that are then missing for the C++ files, can be added to the C++ files themselves.

从每个include文件开始,并确保每个include文件只包含编译本身所需的内容。任何包含的文件,如果是c++文件,都可以添加到c++文件中。

For each include and source file, comment out each include file one at a time and see if it compiles.

对于每个包含和源文件,注释每个包含一个文件一次,看它是否编译。

It is also a good idea to sort the include files alphabetically, and where this is not possible, add a comment.

按字母顺序对include文件进行排序也是一个好主意,如果不可能,可以添加一条注释。

#14


1  

Adding one or both of the following #defines will exclude often unnecessary header files and may substantially improve compile times especially if the code that is not using Windows API functions.

添加以下#define的一个或两个将会排除不必要的头文件,并且可能会大大提高编译时间,特别是如果代码没有使用Windows API函数。

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

See http://support.microsoft.com/kb/166474

参见http://support.microsoft.com/kb/166474

#15


1  

If you aren't already, using a precompiled header to include everything that you're not going to change (platform headers, external SDK headers, or static already completed pieces of your project) will make a huge difference in build times.

如果您还没有修改,那么使用预编译的头文件来包含您不打算更改的所有内容(平台头文件、外部SDK头文件或项目的静态已完成部分)将在构建时间上产生巨大的差异。

http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx

http://msdn.microsoft.com/en-us/library/szfdksca(VS.71). aspx

Also, although it may be too late for your project, organizing your project into sections and not lumping all local headers to one big main header is a good practice, although it takes a little extra work.

此外,尽管对您的项目来说可能已经太晚了,但是将项目组织成各个部分,而不是将所有本地头集中到一个大的主头是一个很好的实践,尽管这需要一些额外的工作。

#16


1  

If you would work with Eclipse CDT you could try out http://includator.com to optimize your include structure. However, Includator might not know enough about VC++'s predefined includes and setting up CDT to use VC++ with correct includes is not built into CDT yet.

如果您愿意使用Eclipse CDT,您可以尝试http://includator.com来优化包含结构。但是,Includator对VC++的预定义包含可能了解的不够多,并且还没有将CDT设置为使用正确包含的vc++。

#17


1  

The latest Jetbrains IDE, CLion, automatically shows (in gray) the includes that are not used in the current file.

最新的Jetbrains IDE CLion会自动显示(灰色部分)当前文件中没有使用的内容。

It is also possible to have the list of all the unused includes (and also functions, methods, etc...) from the IDE.

也可以从IDE中获得所有未使用的include(以及函数、方法等)的列表。

#18


0  

Some of the existing answers state that it's hard. That's indeed true, because you need a full compiler to detect the cases in which a forward declaration would be appropriate. You cant parse C++ without knowing what the symbols mean; the grammar is simply too ambiguous for that. You must know whether a certain name names a class (could be forward-declared) or a variable (can't). Also, you need to be namespace-aware.

一些现有的答案表明这很难。这确实是正确的,因为您需要一个完整的编译器来检测正向声明在哪些情况下是合适的。如果不知道符号的含义,就不能解析c++;语法太模糊了。您必须知道一个特定的名称是否命名了一个类(可以向前声明)或一个变量(不能)。此外,您需要具有名称空间感知能力。

#19


0  

Maybe a little late, but I once found a WebKit perl script that did just what you wanted. It'll need some adapting I believe (I'm not well versed in perl), but it should do the trick:

可能有点晚了,但是我曾经找到了一个WebKit perl脚本,它完成了您想要的。我认为它需要进行一些调整(我对perl不是很熟悉),但它应该具有以下特点:

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

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

(this is an old branch because trunk doesn't have the file anymore)

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

#20


0  

If there's a particular header that you think isn't needed anymore (say string.h), you can comment out that include then put this below all the includes:

如果有一个你认为不再需要的标题(比如string.h),你可以注释掉那个include,然后把这个放在所有include下面:

#ifdef _STRING_H_
#  error string.h is included indirectly
#endif

Of course your interface headers might use a different #define convention to record their inclusion in CPP memory. Or no convention, in which case this approach won't work.

当然,您的接口头可能使用不同的#define约定来在CPP内存中记录它们的包含。或者没有约定,在这种情况下,这种方法行不通。

Then rebuild. There are three possibilities:

然后重建。有三种可能性:

  • It builds ok. string.h wasn't compile-critical, and the include for it can be removed.

    它构建好了。字符串。h不是编译关键字,它的包含可以被删除。

  • The #error trips. string.g was included indirectly somehow You still don't know if string.h is required. If it is required, you should directly #include it (see below).

    错误#旅行。字符串。g是间接包含的你还是不知道弦。h是必需的。如果需要,您应该直接#include它(参见下面)。

  • You get some other compilation error. string.h was needed and isn't being included indirectly, so the include was correct to begin with.

    你会得到一些其他的编译错误。字符串。h是需要的,并且没有被间接包含,所以include是正确的开始。

Note that depending on indirect inclusion when your .h or .c directly uses another .h is almost certainly a bug: you are in effect promising that your code will only require that header as long as some other header you're using requires it, which probably isn't what you meant.

注意,当.h或.c直接使用另一个.h时,依赖于间接包含,几乎可以肯定这是一个bug:您实际上承诺,只要您使用的其他标头需要标头,那么您的代码将只需要该标头,这可能不是您的意思。

The caveats mentioned in other answers about headers that modify behavior rather that declaring things which cause build failures apply here as well.

其他关于修改行为而不是声明导致构建失败的消息头的回答中提到的注意事项也适用于这里。

#1


45  

While it won't reveal unneeded include files, Visual studio has a setting /showIncludes (right click on a .cpp file, Properties->C/C++->Advanced) that will output a tree of all included files at compile time. This can help in identifying files that shouldn't need to be included.

虽然它不会显示不需要的文件,但是Visual studio有一个设置/ showinclude(右击一个.cpp文件,属性->C/ c++ ->Advanced),它将在编译时输出所有包含文件的树。这有助于识别不需要包含的文件。

You can also take a look at the pimpl idiom to let you get away with fewer header file dependencies to make it easier to see the cruft that you can remove.

您还可以查看pimpl习惯用法,以减少头文件依赖,以便更容易看到可以删除的cruft。

#2


28  

PC Lint works quite well for this, and it finds all sorts of other goofy problems for you too. It has command line options that can be used to create External Tools in Visual Studio, but I've found that the Visual Lint addin is easier to work with. Even the free version of Visual Lint helps. But give PC-Lint a shot. Configuring it so it doesn't give you too many warnings takes a bit of time, but you'll be amazed at what it turns up.

PC Lint在这方面工作得很好,它还为您发现了其他各种各样的问题。它有命令行选项,可以用来在Visual Studio中创建外部工具,但是我发现Visual Lint addin更容易使用。甚至免费版的Visual Lint也有帮助。但是给PC-Lint一个机会。配置它以使它不会给您带来太多的警告需要一些时间,但是您会对它的出现感到惊讶。

#3


26  

There's a new Clang-based tool, include-what-you-use, that aims to do this.

有一种新的基于铿锵的工具,包括“你用什么”,旨在实现这一点。

#4


25  

!!DISCLAIMER!! I work on a commercial static analysis tool (not PC Lint). !!DISCLAIMER!!

! !免责声明! !我从事商业静态分析工具(不是PC Lint)。! !免责声明! !

There are several issues with a simple non parsing approach:

使用简单的非解析方法有几个问题:

1) Overload Sets:

1)过载集:

It's possible that an overloaded function has declarations that come from different files. It might be that removing one header file results in a different overload being chosen rather than a compile error! The result will be a silent change in semantics that may be very difficult to track down afterwards.

重载函数可能有来自不同文件的声明。删除一个头文件可能会导致选择不同的重载,而不是编译错误!结果将是语义上的一种无声的变化,在之后可能很难找到。

2) Template specializations:

2)模板专门化:

Similar to the overload example, if you have partial or explicit specializations for a template you want them all to be visible when the template is used. It might be that specializations for the primary template are in different header files. Removing the header with the specialization will not cause a compile error, but may result in undefined behaviour if that specialization would have been selected. (See: Visibility of template specialization of C++ function)

与重载示例类似,如果您对模板有部分或显式的专门化,那么在使用模板时,您希望它们都是可见的。主要模板的专门化可能在不同的头文件中。使用专门化删除标头不会导致编译错误,但如果选择了专门化,则可能导致未定义的行为。(参见:c++函数模板专门化的可见性)

As pointed out by 'msalters', performing a full analysis of the code also allows for analysis of class usage. By checking how a class is used though a specific path of files, it is possible that the definition of the class (and therefore all of its dependnecies) can be removed completely or at least moved to a level closer to the main source in the include tree.

正如“msalters”所指出的,对代码执行完整的分析也允许分析类的使用。通过检查一个类如何使用特定的文件路径,可能会完全删除类的定义(因此所有的依赖项),或者至少移动到更接近包含树中的主源的级别。

#5


10  

I don't know of any such tools, and I have thought about writing one in the past, but it turns out that this is a difficult problem to solve.

我不知道有任何这样的工具,我以前也想过写一个,但结果证明这是一个很难解决的问题。

Say your source file includes a.h and b.h; a.h contains #define USE_FEATURE_X and b.h uses #ifdef USE_FEATURE_X. If #include "a.h" is commented out, your file may still compile, but may not do what you expect. Detecting this programatically is non-trivial.

说你的源文件包含一个。h和b.h;一个。h包含#define USE_FEATURE_X和b。使用# ifdef USE_FEATURE_X h。如果# include "。h"被注释掉了,你的文件可能仍然被编译,但是可能不会做你所期望的。以编程的方式检测它是非常重要的。

Whatever tool does this would need to know your build environment as well. If a.h looks like:

无论使用什么工具,都需要了解您的构建环境。如果一个。h的样子:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

Then USE_FEATURE_X is only defined if WINNT is defined, so the tool would need to know what directives are generated by the compiler itself as well as which ones are specified in the compile command rather than in a header file.

然后USE_FEATURE_X只在定义WINNT时才被定义,因此工具需要知道编译器本身生成什么指令,以及在编译命令中指定哪些指令,而不是在头文件中。

#6


9  

Like Timmermans, I'm not familiar with any tools for this. But I have known programmers who wrote a Perl (or Python) script to try commenting out each include line one at a time and then compile each file.

和Timmermans一样,我对任何工具都不熟悉。但是我认识一些程序员,他们编写了一个Perl(或Python)脚本,尝试一次注释掉每个包含第一行,然后编译每个文件。


It appears that now Eric Raymond has a tool for this.

看来Eric Raymond已经有了一个工具。

Google's cpplint.py has an "include what you use" rule (among many others), but as far as I can tell, no "include only what you use." Even so, it can be useful.

谷歌的cpplint。py有一个“包含您使用的内容”规则(包括许多其他规则),但是据我所知,no“只包含您使用的内容”。即便如此,它还是有用的。

#7


5  

If you're interested in this topic in general, you might want to check out Lakos' Large Scale C++ Software Design. It's a bit dated, but goes into lots of "physical design" issues like finding the absolute minimum of headers that need to be included. I haven't really seen this sort of thing discussed anywhere else.

如果您对这个主题感兴趣,您可能想看看Lakos的大型c++软件设计。它有点过时,但涉及到很多“物理设计”问题,比如找到需要包含的标题的绝对最小值。我还没见过其他地方讨论过的东西。

#8


4  

If your header files generally start with

如果你的头文件通常以开头

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif

(as opposed to using #pragma once) you could change that to:

(与一次性使用#pragma不同)您可以将其更改为:

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else 
#pragma message("Someheader.h superfluously included")
#endif

And since the compiler outputs the name of the cpp file being compiled, that would let you know at least which cpp file is causing the header to be brought in multiple times.

由于编译器输出正在编译的cpp文件的名称,这至少可以让您知道哪个cpp文件导致头文件被多次引入。

#9


4  

Give Include Manager a try. It integrates easily in Visual Studio and visualizes your include paths which helps you to find unnecessary stuff. Internally it uses Graphviz but there are many more cool features. And although it is a commercial product it has a very low price.

给予包括经理一个尝试。它很容易在Visual Studio中集成,并可视化您的包含路径,帮助您找到不必要的东西。在内部,它使用Graphviz,但还有许多更酷的特性。虽然它是一种商业产品,但价格很低。

#10


4  

You can build an include graph using C/C++ Include File Dependencies Watcher, and find unneeded includes visually.

您可以使用C/ c++构建一个包含文件依赖的监视器,并且在视觉上发现不需要的内容。

#11


3  

PC-Lint can indeed do this. One easy way to do this is to configure it to detect just unused include files and ignore all other issues. This is pretty straightforward - to enable just message 766 ("Header file not used in module"), just include the options -w0 +e766 on the command line.

PC-Lint确实可以做到这一点。一种简单的方法是将它配置为仅检测未使用的include文件并忽略所有其他问题。这非常简单—要启用消息766(“在模块中不使用头文件”),只需在命令行中包含选项-w0 +e766。

The same approach can also be used with related messages such as 964 ("Header file not directly used in module") and 966 ("Indirectly included header file not used in module").

同样的方法也可以用于相关的消息,如964(“不直接在模块中使用头文件”)和966(“间接包括模块中不使用的头文件”)。

FWIW I wrote about this in more detail in a blog post last week at http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318.

FWIW我上周在http://www.riverblade.co.uk/blog.php?archive= 2008_09_091_archive.xml #3575027665614976318的一篇博客文章中更详细地描述了这一点。

#12


2  

If you are looking to remove unnecessary #include files in order to decrease build times, your time and money might be better spent parallelizing your build process using cl.exe /MP, make -j, Xoreax IncrediBuild, distcc/icecream, etc.

如果您希望删除不必要的#include文件以减少构建时间,您的时间和金钱最好使用cl并行化构建过程。exe /MP, make -j, Xoreax置信构建,distcc/icecream等。

Of course, if you already have a parallel build process and you're still trying to speed it up, then by all means clean up your #include directives and remove those unnecessary dependencies.

当然,如果您已经有一个并行的构建过程,并且您还在试图加快它的速度,那么通过所有的方法清除您的#include指令并删除那些不必要的依赖项。

#13


2  

Start with each include file, and ensure that each include file only includes what is necessary to compile itself. Any include files that are then missing for the C++ files, can be added to the C++ files themselves.

从每个include文件开始,并确保每个include文件只包含编译本身所需的内容。任何包含的文件,如果是c++文件,都可以添加到c++文件中。

For each include and source file, comment out each include file one at a time and see if it compiles.

对于每个包含和源文件,注释每个包含一个文件一次,看它是否编译。

It is also a good idea to sort the include files alphabetically, and where this is not possible, add a comment.

按字母顺序对include文件进行排序也是一个好主意,如果不可能,可以添加一条注释。

#14


1  

Adding one or both of the following #defines will exclude often unnecessary header files and may substantially improve compile times especially if the code that is not using Windows API functions.

添加以下#define的一个或两个将会排除不必要的头文件,并且可能会大大提高编译时间,特别是如果代码没有使用Windows API函数。

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

See http://support.microsoft.com/kb/166474

参见http://support.microsoft.com/kb/166474

#15


1  

If you aren't already, using a precompiled header to include everything that you're not going to change (platform headers, external SDK headers, or static already completed pieces of your project) will make a huge difference in build times.

如果您还没有修改,那么使用预编译的头文件来包含您不打算更改的所有内容(平台头文件、外部SDK头文件或项目的静态已完成部分)将在构建时间上产生巨大的差异。

http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx

http://msdn.microsoft.com/en-us/library/szfdksca(VS.71). aspx

Also, although it may be too late for your project, organizing your project into sections and not lumping all local headers to one big main header is a good practice, although it takes a little extra work.

此外,尽管对您的项目来说可能已经太晚了,但是将项目组织成各个部分,而不是将所有本地头集中到一个大的主头是一个很好的实践,尽管这需要一些额外的工作。

#16


1  

If you would work with Eclipse CDT you could try out http://includator.com to optimize your include structure. However, Includator might not know enough about VC++'s predefined includes and setting up CDT to use VC++ with correct includes is not built into CDT yet.

如果您愿意使用Eclipse CDT,您可以尝试http://includator.com来优化包含结构。但是,Includator对VC++的预定义包含可能了解的不够多,并且还没有将CDT设置为使用正确包含的vc++。

#17


1  

The latest Jetbrains IDE, CLion, automatically shows (in gray) the includes that are not used in the current file.

最新的Jetbrains IDE CLion会自动显示(灰色部分)当前文件中没有使用的内容。

It is also possible to have the list of all the unused includes (and also functions, methods, etc...) from the IDE.

也可以从IDE中获得所有未使用的include(以及函数、方法等)的列表。

#18


0  

Some of the existing answers state that it's hard. That's indeed true, because you need a full compiler to detect the cases in which a forward declaration would be appropriate. You cant parse C++ without knowing what the symbols mean; the grammar is simply too ambiguous for that. You must know whether a certain name names a class (could be forward-declared) or a variable (can't). Also, you need to be namespace-aware.

一些现有的答案表明这很难。这确实是正确的,因为您需要一个完整的编译器来检测正向声明在哪些情况下是合适的。如果不知道符号的含义,就不能解析c++;语法太模糊了。您必须知道一个特定的名称是否命名了一个类(可以向前声明)或一个变量(不能)。此外,您需要具有名称空间感知能力。

#19


0  

Maybe a little late, but I once found a WebKit perl script that did just what you wanted. It'll need some adapting I believe (I'm not well versed in perl), but it should do the trick:

可能有点晚了,但是我曾经找到了一个WebKit perl脚本,它完成了您想要的。我认为它需要进行一些调整(我对perl不是很熟悉),但它应该具有以下特点:

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

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

(this is an old branch because trunk doesn't have the file anymore)

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

#20


0  

If there's a particular header that you think isn't needed anymore (say string.h), you can comment out that include then put this below all the includes:

如果有一个你认为不再需要的标题(比如string.h),你可以注释掉那个include,然后把这个放在所有include下面:

#ifdef _STRING_H_
#  error string.h is included indirectly
#endif

Of course your interface headers might use a different #define convention to record their inclusion in CPP memory. Or no convention, in which case this approach won't work.

当然,您的接口头可能使用不同的#define约定来在CPP内存中记录它们的包含。或者没有约定,在这种情况下,这种方法行不通。

Then rebuild. There are three possibilities:

然后重建。有三种可能性:

  • It builds ok. string.h wasn't compile-critical, and the include for it can be removed.

    它构建好了。字符串。h不是编译关键字,它的包含可以被删除。

  • The #error trips. string.g was included indirectly somehow You still don't know if string.h is required. If it is required, you should directly #include it (see below).

    错误#旅行。字符串。g是间接包含的你还是不知道弦。h是必需的。如果需要,您应该直接#include它(参见下面)。

  • You get some other compilation error. string.h was needed and isn't being included indirectly, so the include was correct to begin with.

    你会得到一些其他的编译错误。字符串。h是需要的,并且没有被间接包含,所以include是正确的开始。

Note that depending on indirect inclusion when your .h or .c directly uses another .h is almost certainly a bug: you are in effect promising that your code will only require that header as long as some other header you're using requires it, which probably isn't what you meant.

注意,当.h或.c直接使用另一个.h时,依赖于间接包含,几乎可以肯定这是一个bug:您实际上承诺,只要您使用的其他标头需要标头,那么您的代码将只需要该标头,这可能不是您的意思。

The caveats mentioned in other answers about headers that modify behavior rather that declaring things which cause build failures apply here as well.

其他关于修改行为而不是声明导致构建失败的消息头的回答中提到的注意事项也适用于这里。