c++ - usan - que es tags h1 y cursiva
¿Herramientas para encontrar encabezados incluidos que no se utilizan? (9)
Aquí hay un script que lo hace:
#!/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
Sé que PC-Lint puede informarle sobre los encabezados que se incluyen pero no se usan. ¿Hay alguna otra herramienta que pueda hacer esto, preferiblemente en Linux?
Tenemos una gran base de código que a lo largo de los últimos 15 años ha visto una gran cantidad de funcionalidades moverse, pero rara vez se eliminan las directivas #include sobrantes cuando la funcionalidad se mueve de un archivo de implementación a otro, dejándonos con bastante confusión en este punto. Obviamente, puedo hacer la laboriosa tarea de eliminar todas las directivas #include y dejar que el compilador me diga cuáles incluir, pero prefiero resolver el problema a la inversa, encontrar las que no se utilizaron, en lugar de reconstruir una lista de las usadas.
Eche un vistazo a Dehydra .
Desde el sitio web:
Dehydra es una herramienta de análisis estático, liviana, programable y de uso general, capaz de análisis específicos de la aplicación del código C ++. En el sentido más simple, se puede pensar en Dehydra como una herramienta semántica de grep.
Debería ser posible encontrar un script que verifique los archivos #include no utilizados.
El cppclean de Google parece hacer un trabajo decente al encontrar archivos de encabezado sin usar. Solo comencé a usarlo. Produce algunos falsos positivos. A menudo encontrará inclusiones innecesarias en los archivos de encabezado, pero lo que no le dirá es que necesita una declaración directa de la clase asociada, y la inclusión debe moverse al archivo fuente asociado.
He hecho esto manualmente y vale la pena en el corto plazo (Oh, ¿es el término a largo plazo? - Toma mucho tiempo) debido a un tiempo de compilación reducido:
- Menos encabezados para analizar por cada archivo cpp.
- Menos dependencias: el mundo entero no necesita volver a compilar después de un cambio en un encabezado.
También es un proceso recursivo: cada archivo de encabezado que permanece en las necesidades debe examinarse para ver si se puede eliminar cualquier archivo de encabezado que incluya. Además, a veces puede sustituir las declaraciones directas por encabezados.
Luego, todo el proceso debe repetirse cada pocos meses / año para mantenerse al tanto de los encabezados restantes.
En realidad, estoy un poco molesto con los compiladores de C ++, deberían poder decirle lo que no se necesita: el compilador de Microsoft puede decirle cuándo un cambio en un archivo de encabezado puede ignorarse de manera segura durante la compilación.
La mayoría de los enfoques para eliminar sin usar funcionan mejor si primero se asegura de que cada uno de sus archivos de encabezado se compile por sí mismo. Lo hice de forma relativamente rápida de la siguiente manera (disculpas por los errores tipográficos; estoy escribiendo esto en casa:
find . -name ''*.h'' -exec makeIncluder.sh {} /;
donde makeIncluder.sh
contiene:
#!/bin/sh
echo "#include /"$1/"" > $1.cpp
Para cada archivo ./subdir/classname.h
, este enfoque crea un archivo llamado ./subdir/classname.h.cpp
contiene la línea
#include "./subdir/classname.h"
Si su makefile
en el. directorio compila todos los archivos cpp y contiene -I.
, entonces, al volver a compilar, se probará que cada archivo incluido se puede compilar por sí mismo. Compila tu IDE favorito con goto-error y soluciona los errores.
Cuando termines, find . -name ''*.h.cpp'' -exec rm {} /;
find . -name ''*.h.cpp'' -exec rm {} /;
Por lo que yo sé, no hay uno (que no sea PC-Lint), lo cual es una pena y sorprendente. He visto la sugerencia de hacer este tipo de pseudocódigo (que básicamente es la automatización de su "proceso minucioso":
por cada archivo cpp
por cada encabezado incluido
comentar el incluir
compilar el archivo cpp
if (compile_errors)
des-comentar el encabezado
más
eliminar encabezado incluir desde cpp
Ponlo en un cron nocturno, y debería hacer el trabajo, manteniendo el proyecto en cuestión libre de encabezados no utilizados (siempre puedes ejecutarlo manualmente, obviamente, pero llevará mucho tiempo ejecutarlo). El único problema es cuando no incluir un encabezado no genera un error, pero aún produce código.
Si alguien está interesado, acabo de poner en sourceforge una pequeña herramienta Java línea de comando para hacer exactamente eso. Como está escrito en Java, obviamente es ejecutable en Linux.
El enlace para el proyecto es https://sourceforge.net/projects/chksem/files/chksem-1.0/
Si está utilizando Eclipse CDT, puede probar el Includator, que es gratuito para los beta testers (en el momento de escribir esto) y elimina automáticamente #includes superfluos o agrega los que faltan.
Descargo de responsabilidad: trabajo para la compañía que desarrolla el Includator y lo he usado durante los últimos meses. Funciona bastante bien para mí, así que pruébalo :-)
DESCARGO DE RESPONSABILIDAD: Mi trabajo diario está funcionando para una empresa que desarrolla herramientas de análisis estático.
Me sorprendería que la mayoría de las herramientas de análisis estático (si no todas) no tuvieran algún tipo de verificación de uso del encabezado. Puede usar this página de wikipedia para obtener una lista de las herramientas disponibles y luego enviarlas por correo electrónico a las empresas para que las consulten.
Algunos puntos que puede considerar al evaluar una herramienta:
Para las sobrecargas de funciones, desea que todos los encabezados que contienen sobrecargas estén visibles, no solo el encabezado que contiene la función que se seleccionó mediante la resolución de sobrecarga:
// 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
}
Si adoptas el enfoque de la fuerza bruta, primero quita todos los encabezados y luego vuelve a agregarlos hasta que se compile, si primero se agrega ''f1.h'', el código se compilará pero la semántica del programa se habrá modificado.
Una regla similar se aplica cuando tienes parcializaciones y especializaciones. No importa si la especialización está seleccionada o no, debe asegurarse de que todas las especializaciones estén visibles:
// 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)''
}
En cuanto al ejemplo de sobrecarga, el enfoque de fuerza bruta puede dar como resultado un programa que aún compila pero tiene un comportamiento diferente.
Otro tipo de análisis relacionado que puede tener en cuenta es verificar si los tipos pueden declararse hacia adelante. Considera lo siguiente:
// 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);
}
En el ejemplo anterior, la definición de ''A'' no es necesaria, por lo que el archivo de encabezado ''foo.h'' se puede cambiar para que tenga una declaración directa solo para ''A'':
// foo.h
class A;
void foo (A const &);
Este tipo de control también reduce las dependencias del encabezado.