A colleague recently revealed to me that a single source file of ours includes over 3,400 headers during compile time. We have over 1,000 translation units that get compiled in a build, resulting in a huge performance penalty over headers that surely aren't all used.
Are there any static analysis tools that would be able to shed light on the trees in such a forest, specifically giving us the ability to decide which ones we should work on paring out?
UPDATE
Found some interesting information on the cost of including a header file (and the types of include guards to optimize its inclusion) here, originating from this question.
SonarQube is the popular static analysis tool for continuously inspecting the code quality and security of your codebases and guiding development teams during code reviews. SonarQube is used for automated code review with CI/CD Integration.
CppDepend is a commercial static code analysis tool for C++. It can complement other static code analysis tools quite easily as it focuses on analyzing and visualizing the code base architecture (for example, whether it is layered correctly, dependencies-wise), rather than on revealing errors.
Klocwork is a static code analysis tool owned by Minneapolis, Minnesota-based software developer Perforce. Klocwork software analyzes source code in real time, simplifies peer code reviews, and extends the life of complex software.
To avoid multiple inclusions of the same header file we use the #ifndef, #define and #endif preprocessor directives. Just write the entire program in only file and include headers once only.
The output of gcc -w -H <file>
might be useful (If you parse it and put some counts in) the -w
is there to suppress all warnings, which might be awkward to deal with.
From the gcc docs:
-H
Print the name of each header file used, in addition to other normal activities. Each name is indented to show how deep in the
#include
stack it is. Precompiled header files are also printed, even if they are found to be invalid; an invalid precompiled header file is printed with...x
and a valid one with...!
.
The output looks like this:
. /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
If you are using gcc/g++, the -M
or -MM
option will output a line with the information you seek. (The former will include system headers while the latter will not. There are other variants; see the 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
You would need to remove the foo.o: foo.c
at the beginning, but the rest is a list of all headers that the file depends on, so it would not be too hard to write a script to gather these and summarize them.
Of course this suggestion is only useful on Unix and only if nobody else has a better idea. :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With