sonar reglas que pruebas kiuwan herramientas fuente estático estatico dinamico código codigo analisis c++ c static-analysis header-files

c++ - reglas - ¿Encabezado de inclusión de archivos de herramientas de análisis estático?



reglas de analisis estatico de codigo (8)

Un colega recientemente me reveló que un único archivo fuente de nuestro incluye más de 3,400 encabezados durante el tiempo de compilación. Tenemos más de 1,000 unidades de traducción que se compilan en una compilación, lo que resulta en una gran penalización de rendimiento para los encabezados que seguramente no se usan todos.

¿Existen herramientas de análisis estático que puedan arrojar luz sobre los árboles en un bosque así, específicamente dándonos la capacidad de decidir cuáles debemos trabajar para eliminarlas?

ACTUALIZAR

Encontré aquí información interesante sobre el costo de incluir un archivo de encabezado (y los tipos de guardas de inclusión para optimizar su inclusión), originado de esta pregunta .


El "Diseño de software C ++ a gran escala" de John Lakos tenía herramientas que extraían las dependencias en tiempo de compilación entre los archivos de origen.

Desafortunadamente, su repositorio en el sitio de Addison-Wesley se ha ido (junto con el sitio de AW), pero encontré un archivo comprimido aquí: http://prdownloads.sourceforge.net/introspector/LSC-rpkg-0.1.tgz?download

Lo encontré útil hace varios trabajos, y tiene la virtud de ser libre.

Por cierto, si no has leído el libro de Lakos, parece que tu proyecto se beneficiaría. (La edición actual es un poco anticuada, pero escuché que Lakos tiene otro libro que saldrá en 2012.)


GCC tiene un indicador -M que generará una lista de dependencias para un archivo fuente dado. Podría usar esa información para averiguar cuál de sus archivos tiene la mayor dependencia, en qué archivos se depende más, etc.

Echa un vistazo a la página de manual para más información. Hay varias variantes de -M .


GCC tiene una marca (-save-temps) con la que puedes guardar archivos intermedios. Esto incluye archivos .ii, que son los resultados del preprocesador (antes de la compilación). Puede escribir un script para analizar esto y determinar el peso / costo / tamaño de lo que se incluye, así como el árbol de dependencias.

Escribí un script en Python para hacer esto (disponible públicamente aquí: https://gitlab.com/p_b_omta/gcc-include-analyzer ).


He oído que hay algunas herramientas que lo hacen, pero no las uso.

Creé que alguna herramienta https://sourceforge.net/p/headerfinder puede ser útil. Desafortunadamente es una herramienta "HOME MADE" con los siguientes problemas,

  • Desarrollado en Vb.Net
  • Código fuente necesario para compilar
  • Muy lento y consume memoria.
  • No hay ayuda disponible.

Personalmente, no sé si hay una herramienta que diga "Eliminar este archivo". Es realmente un asunto complejo que depende de muchas cosas. Mirar un árbol de declaraciones de inclusión seguramente te volverá loco ... Me volvería loco y me arruinaría los ojos. Hay mejores maneras de hacer cosas para reducir los tiempos de compilación.

  1. De-inline sus métodos de clase.
  2. Después de definirlos, vuelva a examinar sus declaraciones de inclusión e intente eliminarlas. Por lo general es útil eliminarlos, y comenzar de nuevo.
  3. Preferir usar declaraciones a plazo son tanto como sea posible. Si desentierra métodos en sus archivos de encabezado, puede hacer esto mucho.
  4. Divida los archivos de encabezado grandes en archivos más pequeños. Si una clase en un archivo se usa con más frecuencia que la mayoría, entonces póngala en un archivo de encabezado por sí misma.
  5. 1000 unidades de traducción no es mucho en realidad. Tenemos entre 10-20 mil. :)
  6. Obtén Incredibuild si tus tiempos de compilación son demasiado largos.

Si está utilizando gcc / g ++, la opción -M o -MM mostrará una línea con la información que busca. (El primero incluirá los encabezados del sistema, mientras que el segundo no lo hará. Hay otras variantes; consulte el manual).

$ gcc -M -c foo.c foo.o: foo.c /usr/include/stdint.h /usr/include/features.h / /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h / /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h / /usr/include/bits/wchar.h

foo.o: foo.c eliminar el foo.o: foo.c al principio, pero el resto es una lista de todos los encabezados de los que depende el archivo, por lo que no sería demasiado difícil escribir un script para recopilarlos y resumirlos.

Por supuesto, esta sugerencia solo es útil en Unix y solo si nadie más tiene una idea mejor. :-)


unas pocas cosas-

  • use "solo preprocesamiento" para ver la salida del preprocesador. Opción gcc -E, otros compiladores también tienen la función

  • Utilice encabezados precompilados.

  • gcc tiene opciones de -verbose y --trace que también muestran el árbol de inclusión completo, MSVC tiene la opción / showIncludes que se encuentra en la página de propiedades de Advanced C ++

Además, muestra la jerarquía #include para un archivo C ++ en Visual Studio


La salida de gcc -w -H <file> puede ser útil (si lo analiza y coloca algunos conteos), la -w está ahí para suprimir todas las advertencias, lo que puede ser incómodo de tratar.

De los documentos gcc:

-H

Imprima el nombre de cada archivo de encabezado utilizado, además de otras actividades normales. Cada nombre está sangrado para mostrar qué tan profundo está en la pila #include . Los archivos de encabezado precompilados también se imprimen, incluso si se considera que no son válidos; un archivo de encabezado precompilado no válido se imprime con ...x uno válido con ...! .

La salida se ve así:

. /usr/include/unistd.h .. /usr/include/features.h ... /usr/include/bits/predefs.h ... /usr/include/sys/cdefs.h .... /usr/include/bits/wordsize.h ... /usr/include/gnu/stubs.h .... /usr/include/bits/wordsize.h .... /usr/include/gnu/stubs-64.h .. /usr/include/bits/posix_opt.h .. /usr/include/bits/environments.h ... /usr/include/bits/wordsize.h .. /usr/include/bits/types.h ... /usr/include/bits/wordsize.h ... /usr/include/bits/typesizes.h .. /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stddef.h .. /usr/include/bits/confname.h .. /usr/include/getopt.h . /usr/include/stdio.h .. /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stddef.h .. /usr/include/libio.h ... /usr/include/_G_config.h .... /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stddef.h .... /usr/include/wchar.h ... /usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/include/stdarg.h .. /usr/include/bits/stdio_lim.h .. /usr/include/bits/sys_errlist.h Multiple include guards may be useful for: /usr/include/bits/confname.h /usr/include/bits/environments.h /usr/include/bits/predefs.h /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h /usr/include/bits/typesizes.h /usr/include/gnu/stubs-64.h /usr/include/gnu/stubs.h /usr/include/wchar.h