C++ 用于查找未使用的包含标头的工具?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1301850/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:28:49  来源:igfitidea点击:

Tools to find included headers which are unused?

c++coding-styleheader-files

提问by Nick Bastin

I know PC-Lintcan tell you about headers which are included but not used. Are there any other tools that can do this, preferably on linux?

我知道PC-Lint可以告诉您包含但未使用的标头。有没有其他工具可以做到这一点,最好是在 linux 上?

We have a large codebase that through the last 15 years has seen plenty of functionality move around, but rarely do the leftover #include directives get removed when functionality moves from one implementation file to another, leaving us with a pretty good mess by this point. I can obviously do the painstaking thing of removing all the #include directives and letting the compiler tell me which ones to reinclude, but I'd rather solve the problem in reverse - find the unused ones - rather than rebuilding a list of used ones.

我们有一个庞大的代码库,在过去的 15 年里,它见证了大量功能的移动,但是当功能从一个实现文件移动到另一个实现文件时,很少会删除剩余的 #include 指令,这让我们现在一团糟。我显然可以完成删除所有 #include 指令并让编译器告诉我重新包含哪些指令的艰苦工作,但我宁愿反向解决问题 - 找到未使用的 - 而不是重建已使用的列表。

采纳答案by Richard Corden

DISCLAIMER:My day job is working for a company that develops static analysis tools.

免责声明:我的日常工作是为一家开发静态分析工具的公司工作。

I would be surprised if most (if not all) static analysis tools did not have some form of header usage check. You could use thiswikipedia page to get a list of available tools and then email the companies to ask them.

如果大多数(如果不是全部)静态分析工具没有某种形式的标头使用检查,我会感到惊讶。您可以使用维基百科页面获取可用工具列表,然后通过电子邮件向公司询问。

Some points you might consider when you're evaluating a tool:

在评估工具时,您可能会考虑以下几点:

For function overloads, you want all headers containing overloads to be visible, not just the header that contains the function that was selected by overload resolution:

对于函数重载,您希望包含重载的所有标头都可见,而不仅仅是包含通过重载解析选择的函数的标头:

// f1.h
void foo (char);

// f2.h
void foo (int);


// bar.cc
#include "f1.h"
#include "f2.h"

int main ()
{
  foo (0);  // Calls 'foo(int)' but all functions were in overload set
}

If you take the brute force approach, first remove all headers and then re-add them until it compiles, if 'f1.h' is added first then the code will compile but the semantics of the program have been changed.

如果你采用蛮力方法,首先删除所有头文件,然后重新添加它们直到编译,如果先添加'f1.h',那么代码将编译,但程序的语义已更改。

A similar rule applies when you have partial and specializations. It doesn't matter if the specialization is selected or not, you need to make sure that all specializations are visible:

当您有部分和专业化时,类似的规则适用。是否选择专精并不重要,您需要确保所有专精都可见:

// f1.h
template <typename T>
void foo (T);

// f2.h
template <>
void foo (int);

// bar.cc
#include "f1.h"
#include "f2.h"


int main ()
{
  foo (0);  // Calls specialization 'foo<int>(int)'
}

As for the overload example, the brute force approach may result in a program which still compiles but has different behaviour.

至于重载示例,蛮力方法可能会导致程序仍然可以编译但具有不同的行为。

Another related type of analysis that you can look out for is checking if types can be forward declared. Consider the following:

您可以注意的另一种相关分析类型是检查类型是否可以向前声明。考虑以下:

// A.h
class A { };

// foo.h
#include "A.h"
void foo (A const &);

// bar.cc
#include "foo.h"

void bar (A const & a)
{
  foo (a);
}

In the above example, the definition of 'A' is not required, and so the header file 'foo.h' can be changed so that it has a forward declaration only for 'A':

在上面的例子中,'A' 的定义不是必需的,所以头文件 'foo.h' 可以更改,以便它只对 'A' 有一个前向声明:

// foo.h
class A;
void foo (A const &);

This kind of check also reduces header dependencies.

这种检查还减少了标头依赖性。

回答by Andy C

Here's a script that does it:

这是一个执行此操作的脚本:

#!/bin/bash
# prune include files one at a time, recompile, and put them back if it doesn't compile
# arguments are list of files to check
removeinclude() {
    file=
    header=
    perl -i -p -e 's+([ \t]*#include[ \t][ \t]*[\"\<]''[\"\>])+//REMOVEINCLUDE +' 
}
replaceinclude() {
   file=
   perl -i -p -e 's+//REMOVEINCLUDE ++' 
}

for file in $*
do
    includes=`grep "^[ \t]*#include" $file | awk '{print ;}' | sed 's/[\"\<\>]//g'`
    echo $includes
    for i in $includes
    do
        touch $file # just to be sure it recompiles
        removeinclude $file $i
        if make -j10 >/dev/null  2>&1;
        then
            grep -v REMOVEINCLUDE $file > tmp && mv tmp $file
            echo removed $i from $file
        else
            replaceinclude $file
            echo $i was needed in $file
        fi
    done
done

回答by Chance

Google's cppcleanseems to do a decent job of finding unused header files. I just started using it. It produces a few false positives. It will often find unnecessary includes in header files, but what it will not tell you is that you need a forward declaration of the associated class, and the include needs to be moved to the associated source file.

Google 的cppclean似乎在查找未使用的头文件方面做得不错。我刚开始使用它。它会产生一些误报。它通常会在头文件中发现不必要的包含,但它不会告诉您的是您需要关联类的前向声明,并且需要将包含移动到关联的源文件中。

回答by Ton van den Heuvel

Have a look at Dehydra.

看看脱水

From the website:

从网站:

Dehydra is a lightweight, scriptable, general purpose static analysis tool capable of application-specific analyses of C++ code. In the simplest sense, Dehydra can be thought of as a semantic grep tool.

Dehydra 是一种轻量级、可编写脚本的通用静态分析工具,能够对 C++ 代码进行特定于应用程序的分析。在最简单的意义上,Dehydra 可以被认为是一个语义 grep 工具。

It should be possible to come up with a script that checks for unused #include files.

应该可以想出一个脚本来检查未使用的#include 文件。

回答by Mirko Stocker

If you are using Eclipse CDT you can try Includatorwhich is free for beta testers (at the time of this writing) and automatically removes superfluous #includes or adds missing ones.

如果您正在使用 Eclipse CDT,您可以尝试对 Beta 测试人员免费的Includator(在撰写本文时)并自动删除多余的 #includes 或添加缺少的 #includes。

Disclaimer: I work for the company that develops Includator and have been using it for the past few months. It works quite well for me, so give it a try :-)

免责声明:我在开发 Includator 的公司工作,过去几个月一直在使用它。它对我来说效果很好,所以试一试:-)

回答by Cinder6

As far as I know, there isn't one (that isn't PC-Lint), which is a shame, and surprising. I've seen the suggestion to do this bit of pseudocode (which is basically automating your "painstaking process":

据我所知,没有一个(不是 PC-Lint),这是一种耻辱,令人惊讶。我已经看到了做这一点伪代码的建议(这基本上是自动化你的“艰苦过程”:

for every cpp file
for every header include
comment out the include
compile the cpp file
if( compile_errors )
un-comment out the header
else
remove header include from cpp

对于每个
头文件的每个 cpp 文件包含
注释掉包含
编译 cpp 文件
if(compile_errors)
取消注释掉头
否则
从 cpp 中删除头包含

Put that in a nightly cron, and it should do the job, keeping the projcet in question free of unused headers (you can always run it manually, obviously, but it'll take a long time to execute). Only problem is when not including a header doesn't generate an error, but still produces code.

把它放在每晚的 cron 中,它应该可以完成这项工作,保持有问题的项目没有未使用的标头(显然,您总是可以手动运行它,但执行需要很长时间)。唯一的问题是当不包含标题时不会产生错误,但仍会产生代码。

回答by quamrana

I've done this manually and its worth it in the short (Oh, is it the long term? - It takes a long time) term due to reduced compile time:

由于编译时间减少,我已经手动完成了这项工作,并且在短期内(哦,这是长期的吗? - 这需要很长时间)是值得的:

  1. Less headers to parse for each cpp file.
  2. Less dependencies - the whole world doesn't need re-compiling after a change to one header.
  1. 为每个 cpp 文件解析的标头更少。
  2. 更少的依赖 - 整个世界都不需要在更改一个标头后重新编译。

Its also a recursive process - each header file that stays in needs examining to see if any header files itincludes can be removed. Plus sometimes you can substitute forward declarations for header includes.

它也是一个递归过程——每个停留在其中的头文件都需要检查以查看是否可以删除包含的任何头文件。另外,有时您可以用前向声明替换标头包含。

Then the whole process needs repeating every few months/year to keep on top of leftover headers.

然后整个过程需要每隔几个月/每年重复一次以保持在剩余的标题之上。

Actually, I'm a bit annoyed with C++ compilers, they should be able to tell you what's not needed - the Microsoft compiler can tell you when a change to a header file can be safely ignored during compilation.

实际上,我对 C++ 编译器有点恼火,它们应该能够告诉您什么是不需要的 - Microsoft 编译器可以告诉您何时可以在编译期间安全地忽略对头文件的更改。

回答by Arctica

If someone is interested, I just putted on sourceforge a small Java comand-line tool for doing exactly that. As it is written in Java, it is obviously runable on linux.

如果有人感兴趣,我只是在 sourceforge 上放置了一个小型 Java 命令行工具来完成此操作。由于它是用 Java 编写的,因此显然可以在 linux 上运行。

The link for the project is https://sourceforge.net/projects/chksem/files/chksem-1.0/

该项目的链接是https://sourceforge.net/projects/chksem/files/chksem-1.0/

回答by John Hainsworth

Most approaches for removing unused includes work better if you first make sure that each your header files compiles on its own. I did this relatively quickly as follows (apologies for typos -- I am typing this at home:

如果您首先确保每个头文件都自行编译,则大多数删除未使用的包含的方法会更好地工作。我按如下方式相对较快地完成了此操作(对于错别字深表歉意——我正在家里打字:

find . -name '*.h' -exec makeIncluder.sh {} \;

where makeIncluder.shcontains:

其中makeIncluder.sh包含:

#!/bin/sh
echo "#include \"\"" > .cpp

For each file ./subdir/classname.h, this approach creates a file called ./subdir/classname.h.cppcontaining the line

对于每个文件./subdir/classname.h,此方法会创建一个名为的文件,./subdir/classname.h.cpp其中包含该行

#include "./subdir/classname.h"

If your makefilein the . directory compiles all cpp files and contains -I., then just recompiling will test that every include file can compile on its own. Compile in your favorite IDE with goto-error, and fix the errors.

如果您makefile在 . 目录编译所有 cpp 文件和 contains -I.,然后重新编译将测试每个包含文件都可以自己编译。使用 goto-error 在您喜欢的 IDE 中编译,并修复错误。

When you're done, find . -name '*.h.cpp' -exec rm {} \;

完成后, find . -name '*.h.cpp' -exec rm {} \;