我应该如何检测大型 C++ 项目中不必要的 #include 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/74326/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How should I detect unnecessary #include files in a large C++ project?
提问by shambolic
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 #include
s 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
s 只是工件,在删除它们后一切都会很好地编译,而在其他情况下,可以向前声明类,并且可以将 #include 移动到.cpp
文件中。有没有什么好的工具可以检测这两种情况?
采纳答案by Eclipse
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 有一个设置/showIncludes
(右键单击.cpp
文件Properties->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 idiom,以减少头文件依赖项,从而更轻松地查看可以删除的内容。
回答by Joe
PC Lintworks 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 Lintaddin 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插件更易于使用。即使是免费版的 Visual Lint 也有帮助。但是给 PC-Lint 一个机会。配置它以便它不会给您太多警告需要一些时间,但您会惊讶于它出现的情况。
回答by Josh Kelley
There's a new Clang-based tool, include-what-you-use, that aims to do this.
有一个新的基于 Clang 的工具,include-what-you-use,旨在做到这一点。
回答by Richard Corden
!!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' 所指出的,对代码进行全面分析还可以分析类的使用情况。通过检查文件的特定路径如何使用类,可以完全删除类的定义(以及因此它的所有依赖项),或者至少将其移动到更接近包含中的主要源的级别树。
回答by Graeme Perrow
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 programaticallyis non-trivial.
假设您的源文件包含 ah 和 bh;ah 包含#define USE_FEATURE_X
和 bh 使用#ifdef USE_FEATURE_X
. 如果#include "a.h"
被注释掉,您的文件可能仍然可以编译,但可能不会按照您的预期进行。以编程方式检测这一点并非易事。
Whatever tool does this would need to know your build environment as well. If a.h looks like:
无论使用什么工具,都需要了解您的构建环境。如果 ah 看起来像:
#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.
thenUSE_FEATURE_X
仅在定义时才定义WINNT
,因此该工具需要知道编译器本身生成了哪些指令,以及哪些指令是在 compile 命令中指定的,而不是在头文件中指定的。
回答by Max Lybbert
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.pyhas an "include what you use" rule (among many others), but as far as I can tell, no "include onlywhat you use." Even so, it can be useful.
谷歌的cpplint.py有一个“包括你使用的”规则(以及许多其他规则),但据我所知,没有“只包括你使用的”。即便如此,它仍然很有用。
回答by Adrian
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++ 软件设计。它有点过时,但涉及许多“物理设计”问题,例如找到需要包含的绝对最小标题。我还没有真正看到过在其他任何地方讨论过这种事情。
回答by Alex
Give Include Managera 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,但还有更多很酷的功能。虽然它是一种商业产品,但它的价格非常低。
回答by Vladimir
You can build an include graph using C/C++ Include File Dependencies Watcher, and find unneeded includes visually.
您可以使用C/C++ Include File Dependencies Watcher构建包含图,并直观地查找不需要的包含。
回答by Sam
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 once 相反)您可以将其更改为:
#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 文件导致头文件被多次引入。