¿Cómo debo detectar archivos #include innecesarios en un proyecto grande de C++?


Estoy trabajando en un gran proyecto de C++ en Visual Studio 2008, y hay muchos archivos con directivas #include 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 ser declaradas forward y el #include podría ser movido al archivo .cpp. ¿Existen buenas herramientas para detectar estos dos casos?

Author: LogicStuff, 2008-09-16

20 answers

Si bien no revelará archivos de inclusión innecesarios, Visual studio tiene una configuración /showIncludes (haga clic con el botón derecho en un archivo .cpp, Properties->C/C++->Advanced) que generará un árbol de todos los archivos incluidos en tiempo de compilación. Esto puede ayudar a identificar archivos que no deberían ser incluidos.

También puede echar un vistazo al modismo pimpl para que pueda salirse con la suya con menos dependencias de archivos de encabezado para que sea más fácil ver el cruft que puede eliminar.

 45
Author: Eclipse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-22 22:49:10

PC Lint funciona bastante bien para esto, y encuentra todo tipo de otros problemas tontos para usted también. Tiene opciones de línea de comandos que se pueden usar para crear Herramientas externas en Visual Studio, pero he encontrado que el complemento Visual Lint es más fácil de trabajar. Incluso la versión gratuita de Visual Lint ayuda. Pero dale a PC-Lint una oportunidad. Configurarlo para que no te dé demasiadas advertencias lleva un poco de tiempo, pero te sorprenderá lo que aparece.

 28
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 17:34:20

Hay una nueva herramienta basada en Clang, include-what-you-use, que tiene como objetivo hacer esto.

 26
Author: Josh Kelley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-05 14:56:32

!!DESCARGO DE RESPONSABILIDAD!! Trabajo en una herramienta de análisis estático comercial (no pelusa de PC). !!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 provienen de archivos diferentes. Podría ser que la eliminación de un archivo de encabezado resulta en una sobrecarga diferente que se elige 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 localízalo después.

2) Especializaciones de plantilla:

Similar al ejemplo de sobrecarga, si tiene especializaciones parciales o explícitas para una plantilla, desea que todas sean visibles cuando se use la plantilla. Puede ser que las especializaciones para la plantilla principal estén 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 plantillas de la función C++ )

Como señala 'msalters', realizar un análisis completo del código también permite el análisis del uso de clases. 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 dependnecies) se pueda eliminar completamente o al menos mover a un nivel más cercano a la fuente principal en el árbol de inclusión.

 25
Author: Richard Corden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:04

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.

Digamos que tu archivo fuente incluye a.h y b.h; a.h contiene #define USE_FEATURE_X y b.h usa #ifdef USE_FEATURE_X. Si #include "a.h" es comentado, su archivo todavía puede compilar, pero puede que no haga lo que espera. Detectar este programáticamente no es trivial.

Sea cual sea la herramienta que haga esto, también tendrá que conocer su entorno de compilación. Si a. h se ve como:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

Entonces USE_FEATURE_X solo se define si WINNT está definido, por lo que la herramienta necesitaría saber qué directivas son generadas por el propio compilador, así como cuáles se especifican en el comando compile en lugar de en un archivo de encabezado.

 10
Author: Graeme Perrow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 17:00:00

Al igual que Timmermans, no estoy familiarizado con ninguna herramienta para esto. Pero he conocido programadores que escribieron un script Perl (o Python) para intentar comentar cada línea include una a la vez y luego compilar cada archivo.


Parece que ahora Eric Raymond tiene una herramienta para esto.

De Google cpplint.py tiene una regla de "incluye lo que usas" (entre muchas otras), pero por lo que puedo decir, no "incluye solo lo que usas."Aun así, puede ser útil.

 9
Author: Max Lybbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-13 20:09:08

Si te interesa este tema en general, quizás te interese revisar Large Scale C++ Software Design 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.

 5
Author: Adrian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-07 21:19:03

Si sus archivos de encabezado generalmente comienzan con

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif

(a diferencia de usar #pragma una vez) puedes cambiarlo a:

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else 
#pragma message("Someheader.h superfluously included")
#endif

Y dado que el compilador muestra el nombre del archivo cpp que se está compilando, eso le permitiría saber al menos qué archivo cpp está causando que el encabezado se introduzca varias veces.

 4
Author: Sam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-21 00:40:49

Pruebe Include Manager. Se integra fácilmente en Visual Studio y visualiza sus rutas de inclusión que le ayuda a encontrar cosas innecesarias. Internamente utiliza Graphviz, pero hay muchas más características interesantes. Y aunque es un producto comercial tiene un precio muy bajo.

 4
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-01 11:48:35

Puede construir un gráfico de inclusión usando C/C++ Include File Dependencies Watcher, y encontrar inclusiones innecesarias visualmente.

 4
Author: Vladimir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-30 08:32:26

PC-Lint puede hacer esto. Una forma fácil de hacer esto es configurarlo para detectar solo archivos de inclusión no utilizados e ignorar todos los demás problemas. Esto es bastante sencillo: para habilitar solo el mensaje 766 ("Archivo de encabezado no utilizado en el módulo"), solo incluya las opciones - w0 +e766 en la línea de comandos.

El mismo enfoque también se puede usar con mensajes relacionados como 964 ("Archivo de encabezado no utilizado directamente en el módulo") y 966 ("Archivo de encabezado incluido indirectamente no utilizado en el módulo").

FWIW Escribí sobre esto con más detalle en un post de blog la semana pasada en http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 20:42:30

Si está buscando eliminar archivos innecesarios #include para disminuir los tiempos de compilación, su tiempo y dinero podrían gastarse mejor paralelizando su proceso de compilación usando cl.exe /MP, make-j, Xoreax IncrediBuild, distcc/helado, etc.

Por supuesto, si ya tiene un proceso de compilación paralelo y todavía está tratando de acelerarlo, entonces por todos los medios limpie sus directivas #include y elimine esas dependencias innecesarias.

 2
Author: bk1e,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 06:02:15

Comience con cada archivo include, y asegúrese de que cada archivo include solo incluya lo necesario para compilarse. Cualquier archivo de inclusión que falte para los archivos C++, se puede agregar a los propios archivos C++.

Para cada archivo include y fuente, comente cada archivo include uno a la vez 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.

 2
Author: selwyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 16:55:16

Agregar uno o ambos de los siguientes #define excluirá a menudo archivos de encabezado innecesarios y puede mejorar sustancialmente tiempos de compilación, especialmente si el código que no está utilizando funciones de la API de Windows.

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

Véase http://support.microsoft.com/kb/166474

 1
Author: Roger Nelson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 04:28:17

Si aún no lo estás haciendo, usar un encabezado precompilado para incluir todo lo que no vas a cambiar (encabezados de plataforma, encabezados de SDK externos o piezas estáticas ya completadas de tu proyecto) hará una gran diferencia en los tiempos de compilación.

Http://msdn.microsoft.com/en-us/library/szfdksca (VS.71).aspx

También, 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 practica, aunque requiere un poco de trabajo extra.

 1
Author: anon6439,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 11:12:51

Si trabajaras con Eclipse CDT podrías 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 que la configuración de CDT para usar VC++ con inclusiones correctas aún no esté integrada en CDT.

 1
Author: PeterSom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-01 12:44:43

El último IDE de Jetbrains, CLion, muestra automáticamente (en gris) las inclusiones que no se utilizan en el archivo actual.

También es posible tener la lista de todos los includes no utilizados (y también funciones, métodos, etc...) del IDE.

 1
Author: Jean-Michaël Celerier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-26 21:08:59

Algunas de las respuestas existentes indican que es difícil. Eso es cierto, porque necesita un compilador completo para detectar los casos en los que una declaración forward sería apropiada. No se puede analizar C++ sin saber lo que significan los símbolos; la gramática es simplemente demasiado ambigua para eso. Debe saber si un nombre determinado nombra una clase (podría declararse forward-declared) o una variable (can't). Además, debe tener en cuenta el espacio de nombres.

 0
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 09:17:39

Tal vez un poco tarde, pero una vez encontré un script WebKit perl que hizo justo lo que querías. Necesitará un poco de adaptación creo (no estoy bien versado en perl), pero debería hacer el truco:

Http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes

(esta es una rama antigua porque trunk ya no tiene el archivo)

 0
Author: rubenvb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-30 14:47:08

Si hay un encabezado en particular que crees que ya no es necesario (por ejemplo cadena.h), usted puede comentar que incluyen a continuación, poner esto debajo de todos los incluye:

#ifdef _STRING_H_
#  error string.h is included indirectly
#endif

Por supuesto, los encabezados de la interfaz pueden usar una convención #define diferente para registrar su inclusión en la memoria CPP. O ninguna convención, en cuyo caso este enfoque no funcionará.

A continuación, reconstruir. Hay tres posibilidades:

  • Se construye bien. cadena.h no era compilar-crítico, y el incluir él se puede quitar.

  • El # error trips. cadena.g se incluyó indirectamente de alguna manera Todavía no sabes si string.h. Si es necesario, debería #incluirlo directamente (ver más abajo).

  • Se obtiene algún otro error de compilación. cadena.h era necesario y no está siendo incluido indirectamente, por lo que el include era correcto para empezar.

Tenga en cuenta que dependiendo de la inclusión indirecta cuando su .h or .c utiliza directamente otro .h es casi ciertamente un error: usted está en efecto prometiendo que su el código solo requerirá ese encabezado siempre y cuando otro encabezado esté usando lo requiere, que probablemente no es lo que querías decir.

Las advertencias mencionadas en otras respuestas sobre encabezados que modifican el comportamiento más bien que declarar cosas que causan fallas de construcción se aplican aquí también.

 0
Author: Britton Kerin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-10 22:12:07