find包含未使用的标题的工具?
我知道PC-Lint可以告诉你有关包含但未使用的标题。 有没有其他工具可以做到这一点,最好在Linux上?
我们有一个很大的代码库,在过去的15年里,有大量的function可以移动,但是当function从一个实现文件移动到另一个时,很less会有剩余的#include指令被删除,这一点让我们感到非常好。 我明显可以做的是去除所有的#include指令,并让编译器告诉我要重新包含哪些内容,但是我宁愿解决这个问题 – find未使用的问题 – 而不是重build一个已经使用过的列表。
免责声明:我的日常工作是为开发静态分析工具的公司工作。
如果大多数(如果不是全部的话)静态分析工具没有某种forms的头部使用检查,我会感到惊讶。 你可以使用这个维基百科页面来获取可用工具列表,然后通过电子邮件发送公司问他们。
您在评估工具时可能会考虑以下几点:
对于函数重载,您希望包含重载的所有头文件都可见,而不仅仅是包含通过重载parsingselect的函数的头文件:
// 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 }
如果你采取暴力破解的方法,首先删除所有头文件,然后重新添加它们直到它被编译,如果先添加'f1.h',代码将会被编译,但是程序的语义已经被改变了。
当你有部分和专业化时,也有类似的规则。 不pipe是否select了专业化,都需要确保所有专业化都是可见的:
// 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)' }
至于过载的例子,蛮力的方法可能会导致一个程序仍然编译,但具有不同的行为。
你可以注意的另一种相关的分析types是检查types是否可以被前向声明。 考虑以下:
// Ah class A { }; // foo.h #include "Ah" void foo (A const &); // bar.cc #include "foo.h" void bar (A const & a) { foo (a); }
在上面的例子中,'A'的定义是不需要的,所以头文件'foo.h'可以被改变,所以它只有'A'的前向声明:
// foo.h class A; void foo (A const &);
这种检查也减less了标题依赖性。
这是一个脚本:
#!/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=$1 header=$2 perl -i -p -e 's+([ \t]*#include[ \t][ \t]*[\"\<]'$2'[\"\>])+//REMOVEINCLUDE $1+' $1 } replaceinclude() { file=$1 perl -i -p -e 's+//REMOVEINCLUDE ++' $1 } for file in $* do includes=`grep "^[ \t]*#include" $file | awk '{print $2;}' | 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
看看Dehydra 。
从网站:
Dehydra是一个轻量级,可脚本化的通用静态分析工具,可以对C ++代码进行特定于应用程序的分析。 在最简单的意义上,Dehydra可以被认为是一个语义grep工具。
应该可以想出一个脚本来检查未使用的#include文件。
谷歌的cppclean似乎做了一个体面的工作find未使用的头文件。 我刚开始使用它。 它会产生一些误报。 它通常会在头文件中find不必要的包含,但是它不会告诉你的是你需要关联类的前向声明,并且包含需要被移动到关联的源文件中。
如果您正在使用Eclipse CDT,则可以尝试用于betatesting人员的免费版本(在编写本文时),并自动删除多余的#includes或添加缺less的。
免责声明:我为开发includdator的公司工作,并在过去几个月里一直使用它。 它适合我,所以试试看:-)
据我所知,没有一个(这不是PC-Lint),这是一个耻辱,令人惊讶。 我已经看到了build议做这个伪代码(这基本上是自动化你的“苦心的过程”:
为每个cpp文件
为每个头包括
包括注释掉
编译cpp文件
如果(compile_errors)
取消注释掉标题
其他
从cpp中删除头文件
把它放在一个晚上的cron中,它应该完成这个工作,保持没有使用的头文件(你可以总是手动运行它,显然,但执行需要很长时间)。 唯一的问题是当不包括头不会产生错误,但仍然产生的代码。
我已经手动完成了这个工作,并且由于减less了编译时间,所以它的价值在于短期(噢,是长期的吗? – 这需要很长的时间)
- 为每个cpp文件parsing头文件。
- 更less的依赖关系 – 整个世界在更改一个头之后不需要重新编译。
它也是一个recursion的过程 – 每个头文件都需要检查它的头文件是否可以被删除。 另外有时候你可以用前面的声明来replace头文件。
那么整个过程需要每隔几个月/一年重复一次,以保留剩余的标题。
实际上,我对C ++编译器有些恼火,他们应该能够告诉你什么是不需要的 – 微软编译器可以告诉你什么时候可以在编译期间安全地忽略对头文件的更改。
如果有人感兴趣,我只是在sourceforge上做了一个小的Java命令行工具来完成这个工作。 由于它是用Java编写的,所以很明显可以在linux上运行。
该项目的链接是https://sourceforge.net/projects/chksem/files/chksem-1.0/
大多数删除未使用的方法包括更好的工作,如果你首先确保每个头文件自己编译。 我做了这个比较快,如下(道歉错别字 – 我在家里打字:
find . -name '*.h' -exec makeIncluder.sh {} \;
makeIncluder.sh
包含以下内容:
#!/bin/sh echo "#include \"$1\"" > $1.cpp
对于每个./subdir/classname.h
文件,这种方法创build一个名为./subdir/classname.h.cpp
的文件, ./subdir/classname.h.cpp
包含行
#include "./subdir/classname.h"
如果你的makefile
在。 目录编译所有cpp文件并包含-I.
那么只要重新编译就会testing每个include文件都可以自行编译。 用你最喜欢的IDE编译goto-error,并修正错误。
当你完成后, find . -name '*.h.cpp' -exec rm {} \;
find . -name '*.h.cpp' -exec rm {} \;