Инструменты для поиска включенных заголовков, которые не используются?
Я знаю PC-Lint может рассказать вам о заголовках, которые включены, но не используются. Есть ли другие инструменты, которые могут это сделать, желательно на linux?
У нас есть большая база кода, которая за последние 15 лет обнаружила, что много функциональности перемещается, но редко делают оставшиеся директивы #include удаляются, когда функциональность перемещается из одного файла реализации в другой, оставляя нас с довольно хорошим беспорядком эта точка. Я, очевидно, могу сделать кропотливую попытку удалить все директивы #include и позволить компилятору рассказать мне, какие из них нужно повторно включить, но я бы скорее решил проблему в обратном порядке - найти неиспользуемые, а не перестроить список используемых.
Ответы
Ответ 1
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Моя дневная работа работает в компании, которая разрабатывает инструменты статического анализа.
Я был бы удивлен, если бы большинство (если не всех) инструментов статического анализа не имели какой-либо формы проверки использования заголовка. Вы можете использовать эту страницу wikipedia, чтобы получить список доступных инструментов, а затем отправить по электронной почте компании, чтобы спросить их.
Некоторые моменты, которые вы можете рассмотреть при оценке инструмента:
Для перегрузок функций вы хотите, чтобы все заголовки, содержащие перегрузки, были видимыми, а не только заголовок, содержащий функцию, которая была выбрана с помощью разрешения перегрузки:
// 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", тогда код будет скомпилирован, но семантика программы была изменена.
Аналогичное правило применяется, когда у вас есть частичная и специализация. Не имеет значения, выбрана ли специализация или нет, вам нужно убедиться, что все специализации видны:
// 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)'
}
Что касается примера перегрузки, то подход грубой силы может привести к программе, которая все еще компилируется, но имеет другое поведение.
Другим связанным типом анализа, который вы можете посмотреть, является проверка того, могут ли типы быть объявлены вперед. Рассмотрим следующее:
// 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);
}
В приведенном выше примере определение "A" не требуется, поэтому заголовочный файл "foo.h" можно изменить так, чтобы он имел прямое объявление только для "A":
// foo.h
class A;
void foo (A const &);
Этот тип проверки также уменьшает зависимости заголовков.
Ответ 2
Здесь script, который делает это:
#!/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
Ответ 3
Посмотрите Dehydra.
С веб-сайта:
Dehydra - это простой, статический аналитический инструмент общего назначения, предназначенный для анализа кода С++, специфичного для приложения. В самом простом смысле Дегидра можно рассматривать как семантический инструмент grep.
Должно быть возможно создать script, который проверяет неиспользуемые файлы #include.
Ответ 4
Google cppclean, похоже, делает достойную работу по поиску неиспользуемых файлов заголовков. Я только начал использовать его. Он создает несколько ложных срабатываний. Он часто находит ненужные включения в заголовочные файлы, но то, что он вам не скажет, - это то, что вам нужно объявление вперед связанного класса, а включение необходимо перенести в связанный исходный файл.
Ответ 5
Если вы используете Eclipse CDT, вы можете попробовать Includator, который является бесплатным для бета-тестеров (на момент написания этой статьи) и автоматически удаляет лишние # включает или добавляет недостающие.
Отказ от ответственности: я работаю в компании, которая разрабатывает Includator и использует ее в течение последних нескольких месяцев. Это хорошо работает для меня, поэтому попробуйте: -)
Ответ 6
Насколько я знаю, нет ни одного (это не PC-Lint), что является позором и удивительным. Я видел предложение сделать этот бит псевдокода (который в основном автоматизирует ваш "кропотливый процесс":
для каждого файла cpp
для каждого заголовка: закомментируйте включение скомпилировать файл cpp
if (compile_errors)
не комментировать заголовок
остальное
удалить заголовок из cpp
Поместите это в ночной cron, и он должен выполнить эту работу, не допуская, чтобы рассматриваемый projcet был свободен от неиспользуемых заголовков (вы всегда можете запустить его вручную, очевидно, но это займет много времени, чтобы выполнить). Проблема только в том, что не включая заголовок не генерирует ошибку, но все равно производит код.
Ответ 7
Я сделал это вручную, и его стоит в коротком (о, это долгий срок? - Это занимает много времени) из-за сокращения времени компиляции:
- Меньше заголовков для разбора для каждого файла cpp.
- Меньше зависимостей - весь мир не нуждается в повторной компиляции после
изменить на один заголовок.
Его также рекурсивный процесс - каждый заголовочный файл, который остается в поиске, чтобы посмотреть, могут ли быть удалены любые файлы заголовков . Плюс иногда вы можете подставить форвардные объявления для заголовка.
Затем весь процесс нужно повторять каждые несколько месяцев/год, чтобы сохранить верхние части оставшихся заголовков.
На самом деле, меня немного раздражает компилятор С++, они должны быть в состоянии сказать вам, что не нужно - компилятор Microsoft может сказать вам, когда во время компиляции можно безопасно игнорировать изменение файла заголовка.
Ответ 8
Если кому-то интересно, я просто положил на sourceforge небольшой инструмент Java comand-line для выполнения именно этого.
Поскольку он написан на Java, он явно работает на linux.
Ссылка для проекта https://sourceforge.net/projects/chksem/files/chksem-1.0/
Ответ 9
Большинство подходов к удалению неиспользуемых функций работают лучше, если вы сначала убедитесь, что каждый файл заголовка компилируется сам по себе. Я сделал это относительно быстро следующим образом (извинения за опечатки - я печатаю это дома:
find . -name '*.h' -exec makeIncluder.sh {} \;
где makeIncluder.sh
содержит:
#!/bin/sh
echo "#include \"$1\"" > $1.cpp
Для каждого файла ./subdir/classname.h
этот подход создает файл с именем ./subdir/classname.h.cpp
, содержащий строку
#include "./subdir/classname.h"
Если ваш makefile
в. каталог компилирует все файлы cpp и содержит -I.
, тогда просто перекомпиляция проверит, что каждый включенный файл может скомпилироваться сам по себе. Компиляция в вашей любимой IDE с goto-ошибкой и исправление ошибок.
Когда вы закончите, find . -name '*.h.cpp' -exec rm {} \;