Estoy trabajando en un gran proyecto de C ++ en Visual Studio 2008 y hay muchos archivos con #include
directivas innecesarias . A veces, los #include
s son solo artefactos y todo se compilará bien con ellos eliminados, y en otros casos, las clases podrían declararse hacia adelante y el #include podría moverse al .cpp
archivo. ¿Existen buenas herramientas para detectar ambos casos?
fuente
PC Lint funciona bastante bien para esto, y también encuentra todo tipo de problemas tontos para usted. Tiene opciones de línea de comando que se pueden usar para crear herramientas externas en Visual Studio, pero descubrí que es más fácil trabajar con el complemento Visual Lint . Incluso la versión gratuita de Visual Lint ayuda. Pero dale una oportunidad a PC-Lint. Configurarlo para que no le dé demasiadas advertencias lleva un poco de tiempo, pero se sorprenderá de lo que aparece.
fuente
Hay una nueva herramienta basada en Clang, include-what-you-use , que tiene como objetivo hacer esto.
fuente
!!¡¡DESCARGO DE RESPONSABILIDAD!! Trabajo en una herramienta comercial de análisis estático (no en PC Lint). !!¡¡DESCARGO DE RESPONSABILIDAD!!
Hay varios problemas con un enfoque simple sin análisis:
1) Conjuntos de sobrecarga:
Es posible que una función sobrecargada tenga declaraciones que provengan de diferentes archivos. ¡Puede ser que la eliminación de un archivo de encabezado dé como resultado que se elija una sobrecarga diferente en lugar de un error de compilación! El resultado será un cambio silencioso en la semántica que puede ser muy difícil de rastrear después.
2) Especializaciones en plantillas:
Al igual que en el ejemplo de sobrecarga, si tiene especializaciones parciales o explícitas para una plantilla, desea que todas estén visibles cuando se utilice la plantilla. Es posible que las especializaciones para la plantilla principal se encuentren en diferentes archivos de encabezado. Eliminar el encabezado con la especialización no causará un error de compilación, pero puede resultar en un comportamiento indefinido si esa especialización hubiera sido seleccionada. (Ver: Visibilidad de la especialización de plantilla de la función C ++ )
Como lo señaló 'msalters', realizar un análisis completo del código también permite analizar el uso de la clase. Al verificar cómo se usa una clase a través de una ruta específica de archivos, es posible que la definición de la clase (y por lo tanto todas sus dependencias) se pueda eliminar por completo o al menos mover a un nivel más cercano a la fuente principal en la inclusión árbol.
fuente
No conozco ninguna de estas herramientas y he pensado en escribir una en el pasado, pero resulta que este es un problema difícil de resolver.
Supongamos que su archivo fuente incluye ah y bh; ah contiene
#define USE_FEATURE_X
y bh utiliza#ifdef USE_FEATURE_X
. Si#include "a.h"
está comentado, su archivo aún puede compilarse, pero es posible que no haga lo que espera. Detectar esto programáticamente no es trivial.Cualquiera que sea la herramienta que haga esto, también necesitará conocer su entorno de compilación. Si ah se parece a:
Entonces
USE_FEATURE_X
solo se define siWINNT
está definido, por lo que la herramienta necesitaría saber qué directivas genera el propio compilador, así como cuáles se especifican en el comando de compilación en lugar de en un archivo de encabezado.fuente
Como Timmermans, no estoy familiarizado con ninguna herramienta para esto. Pero he conocido programadores que escribieron un script en Perl (o Python) para intentar comentar cada línea incluida una a la vez y luego compilar cada archivo.
Parece que ahora Eric Raymond tiene una herramienta para esto .
El cpplint.py de Google tiene una regla "incluye lo que usas" (entre muchas otras), pero hasta donde yo sé, no "incluye solo lo que usas". Aun así, puede resultar útil.
fuente
Si está interesado en este tema en general, es posible que desee consultar el diseño de software C ++ a gran escala de Lakos . Es un poco anticuado, pero entra en muchos problemas de "diseño físico", como encontrar el mínimo absoluto de encabezados que deben incluirse. Realmente no he visto este tipo de cosas discutidas en ningún otro lugar.
fuente
Prueba Include Manager . Se integra fácilmente en Visual Studio y visualiza sus rutas de inclusión, lo que le ayuda a encontrar cosas innecesarias. Internamente usa Graphviz pero hay muchas más funciones interesantes. Y aunque es un producto comercial tiene un precio muy bajo.
fuente
Puede crear un gráfico de inclusión utilizando C / C ++ Incluir archivo Dependencies Watcher y encontrar visualmente inclusiones innecesarias.
fuente
Si sus archivos de encabezado generalmente comienzan con
(en lugar de usar #pragma una vez) puedes cambiar eso a:
Y dado que el compilador genera el nombre del archivo cpp que se está compilando, eso le permitiría saber al menos qué archivo cpp está causando que el encabezado ingrese varias veces.
fuente
A.h
yB.h
que tanto depende deC.h
y se incluyeA.h
yB.h
, porque se necesita tanto, se va a incluirC.h
dos veces, pero eso está bien, porque el compilador omitirá la segunda vez, y si no lo hizo, usted tiene que recordar incluir siempreC.h
antesA.h
oB.h
terminar en inclusiones mucho más inútiles.De hecho, PC-Lint puede hacer esto. Una forma sencilla de hacerlo es configurarlo para que detecte solo los archivos de inclusión no utilizados e ignore todos los demás problemas. Esto es bastante sencillo: para habilitar solo el mensaje 766 ("Archivo de encabezado no usado en el módulo"), solo incluya las opciones -w0 + e766 en la línea de comando.
El mismo enfoque también se puede usar con mensajes relacionados como 964 ("Archivo de encabezado no usado directamente en el módulo") y 966 ("Archivo de encabezado incluido indirectamente no usado en el módulo").
FWIW Escribí sobre esto con más detalle en una publicación de blog la semana pasada en http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318 .
fuente
Si está buscando eliminar
#include
archivos innecesarios para disminuir los tiempos de compilación, es mejor invertir su tiempo y dinero en paralelizar su proceso de compilación usando cl.exe / MP , make -j , Xoreax IncrediBuild , distcc / icecream , etc.Por supuesto, si ya tiene un proceso de compilación paralelo y todavía está tratando de acelerarlo, entonces limpie sus
#include
directivas y elimine esas dependencias innecesarias.fuente
Comience con cada archivo de inclusión y asegúrese de que cada archivo de inclusión solo incluya lo necesario para compilarse. Cualquier archivo de inclusión que falte para los archivos de C ++ se puede agregar a los archivos de C ++.
Para cada archivo de inclusión y fuente, comente cada archivo de inclusión de uno en uno y vea si se compila.
También es una buena idea ordenar los archivos de inclusión alfabéticamente y, cuando esto no sea posible, agregar un comentario.
fuente
Agregar una o ambas de las siguientes #defines excluirá los archivos de encabezado a menudo innecesarios y puede mejorar sustancialmente los tiempos de compilación, especialmente si el código no utiliza las funciones de la API de Windows.
Consulte http://support.microsoft.com/kb/166474
fuente
Si aún no lo ha hecho, usar un encabezado precompilado para incluir todo lo que no va a cambiar (encabezados de plataforma, encabezados de SDK externos o partes estáticas ya completadas de su proyecto) hará una gran diferencia en los tiempos de compilación.
http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx
Además, aunque puede ser demasiado tarde para su proyecto, organizar su proyecto en secciones y no agrupar todos los encabezados locales en un encabezado principal grande es una buena práctica, aunque requiere un poco de trabajo adicional.
fuente
Si trabajara con Eclipse CDT, podría probar http://includator.com para optimizar su estructura de inclusión. Sin embargo, es posible que Includator no sepa lo suficiente sobre las inclusiones predefinidas de VC ++ y la configuración de CDT para usar VC ++ con las inclusiones correctas aún no está integrada en CDT.
fuente
El IDE de Jetbrains más reciente, CLion, muestra automáticamente (en gris) las inclusiones que no se utilizan en el archivo actual.
También es posible tener la lista de todas las inclusiones no utilizadas (y también funciones, métodos, etc.) del IDE.
fuente
Algunas de las respuestas existentes afirman que es difícil. De hecho, eso es cierto, porque necesita un compilador completo para detectar los casos en los que una declaración directa sería apropiada. No puede analizar C ++ sin saber qué significan los símbolos; la gramática es demasiado ambigua para eso. Debe saber si un nombre determinado nombra una clase (podría declararse hacia adelante) o una variable (no puede). Además, debe tener en cuenta el espacio de nombres.
fuente
Quizás un poco tarde, pero una vez encontré un script perl de WebKit que hacía exactamente lo que querías. Creo que necesitará un poco de adaptación (no estoy muy versado en perl), pero debería funcionar:
http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes
(esta es una rama antigua porque el tronco ya no tiene el archivo)
fuente
Si hay un encabezado en particular que cree que ya no es necesario (por ejemplo, string.h), puede comentar esa inclusión y luego poner esto debajo de todas las inclusiones:
Por supuesto, los encabezados de su interfaz pueden usar una convención #define diferente para registrar su inclusión en la memoria CPP. O sin convención, en cuyo caso este enfoque no funcionará.
Luego reconstruir. Hay tres posibilidades:
Se construye bien. string.h no era crítico para la compilación, y su inclusión se puede eliminar.
Los viajes del #error. string.g se incluyó indirectamente de alguna manera. Aún no sabe si se requiere string.h. Si es necesario, debe #incluirlo directamente (ver más abajo).
Obtiene algún otro error de compilación. string.h era necesario y no se incluye indirectamente, por lo que la inclusión era correcta para empezar.
Tenga en cuenta que dependiendo de la inclusión indirecta cuando su .ho .c usa directamente otro .h es casi seguro que es un error: de hecho, está prometiendo que su código solo requerirá ese encabezado siempre que otro encabezado que esté usando lo requiera, que probablemente no es lo que quisiste decir.
Las advertencias mencionadas en otras respuestas sobre los encabezados que modifican el comportamiento en lugar de declarar cosas que causan fallas de compilación también se aplican aquí.
fuente