[ACCEPTED]-How should I detect unnecessary #include files in a large C++ project?-dependencies
While it won't reveal unneeded include files, Visual 9 studio has a setting /showIncludes
(right click on a 8 .cpp
file, Properties->C/C++->Advanced
) that will output a tree of all 7 included files at compile time. This can 6 help in identifying files that shouldn't 5 need to be included.
You can also take a 4 look at the pimpl idiom to let you get away 3 with fewer header file dependencies to make 2 it easier to see the cruft that you can 1 remove.
PC Lint works quite well for this, and it finds 9 all sorts of other goofy problems for you 8 too. It has command line options that can 7 be used to create External Tools in Visual 6 Studio, but I've found that the Visual Lint addin is 5 easier to work with. Even the free version 4 of Visual Lint helps. But give PC-Lint a 3 shot. Configuring it so it doesn't give 2 you too many warnings takes a bit of time, but 1 you'll be amazed at what it turns up.
!!DISCLAIMER!! I work on a commercial static 29 analysis tool (not PC Lint). !!DISCLAIMER!!
There 28 are several issues with a simple non parsing 27 approach:
1) Overload Sets:
It's possible 26 that an overloaded function has declarations 25 that come from different files. It might 24 be that removing one header file results 23 in a different overload being chosen rather 22 than a compile error! The result will be 21 a silent change in semantics that may be 20 very difficult to track down afterwards.
2) Template 19 specializations:
Similar to the overload 18 example, if you have partial or explicit 17 specializations for a template you want 16 them all to be visible when the template 15 is used. It might be that specializations 14 for the primary template are in different 13 header files. Removing the header with 12 the specialization will not cause a compile 11 error, but may result in undefined behaviour 10 if that specialization would have been selected. (See: Visibility of template specialization of C++ function)
As 9 pointed out by 'msalters', performing a 8 full analysis of the code also allows for 7 analysis of class usage. By checking how 6 a class is used though a specific path of 5 files, it is possible that the definition 4 of the class (and therefore all of its dependnecies) can 3 be removed completely or at least moved 2 to a level closer to the main source in 1 the include tree.
I don't know of any such tools, and I have 14 thought about writing one in the past, but 13 it turns out that this is a difficult problem 12 to solve.
Say your source file includes a.h 11 and b.h; a.h contains #define USE_FEATURE_X
and b.h uses #ifdef USE_FEATURE_X
. If 10 #include "a.h"
is commented out, your file may still compile, but 9 may not do what you expect. Detecting this 8 programatically is non-trivial.
Whatever tool does this 7 would need to know your build environment 6 as well. If a.h looks like:
#if defined( WINNT )
#define USE_FEATURE_X
#endif
Then USE_FEATURE_X
is only 5 defined if WINNT
is defined, so the tool would 4 need to know what directives are generated 3 by the compiler itself as well as which 2 ones are specified in the compile command 1 rather than in a header file.
Like Timmermans, I'm not familiar with any 9 tools for this. But I have known programmers 8 who wrote a Perl (or Python) script to try 7 commenting out each include line one at 6 a time and then compile each file.
It appears 5 that now Eric Raymond has a tool for this.
Google's cpplint.py has an 4 "include what you use" rule (among 3 many others), but as far as I can tell, no 2 "include only what you use." Even 1 so, it can be useful.
If you're interested in this topic in general, you 6 might want to check out Lakos' Large Scale C++ Software Design. It's a 5 bit dated, but goes into lots of "physical 4 design" issues like finding the absolute 3 minimum of headers that need to be included. I 2 haven't really seen this sort of thing discussed 1 anywhere else.
Give Include Manager a try. It integrates easily in Visual 5 Studio and visualizes your include paths 4 which helps you to find unnecessary stuff. Internally 3 it uses Graphviz but there are many more 2 cool features. And although it is a commercial 1 product it has a very low price.
You can build an include graph using C/C++ Include File Dependencies Watcher, and 1 find unneeded includes visually.
If your header files generally start with
#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif
(as 6 opposed to using #pragma once) you could 5 change that to:
#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else
#pragma message("Someheader.h superfluously included")
#endif
And since the compiler outputs 4 the name of the cpp file being compiled, that 3 would let you know at least which cpp file 2 is causing the header to be brought in multiple 1 times.
PC-Lint can indeed do this. One easy way 13 to do this is to configure it to detect 12 just unused include files and ignore all 11 other issues. This is pretty straightforward 10 - to enable just message 766 ("Header 9 file not used in module"), just include 8 the options -w0 +e766 on the command line.
The 7 same approach can also be used with related 6 messages such as 964 ("Header file 5 not directly used in module") and 966 4 ("Indirectly included header file not 3 used in module").
FWIW I wrote about 2 this in more detail in a blog post last 1 week at http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318.
Adding one or both of the following #defines 4 will exclude often unnecessary header files 3 and may substantially improve compile times 2 especially if the code that is not using 1 Windows API functions.
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
If you are looking to remove unnecessary 7 #include
files in order to decrease build times, your 6 time and money might be better spent parallelizing 5 your build process using cl.exe /MP, make -j, Xoreax IncrediBuild, distcc/icecream, etc.
Of 4 course, if you already have a parallel build 3 process and you're still trying to speed 2 it up, then by all means clean up your #include
directives 1 and remove those unnecessary dependencies.
Start with each include file, and ensure 9 that each include file only includes what 8 is necessary to compile itself. Any include 7 files that are then missing for the C++ files, can 6 be added to the C++ files themselves.
For 5 each include and source file, comment out 4 each include file one at a time and see 3 if it compiles.
It is also a good idea to 2 sort the include files alphabetically, and 1 where this is not possible, add a comment.
If you aren't already, using a precompiled 10 header to include everything that you're 9 not going to change (platform headers, external 8 SDK headers, or static already completed 7 pieces of your project) will make a huge 6 difference in build times.
http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx
Also, although 5 it may be too late for your project, organizing 4 your project into sections and not lumping 3 all local headers to one big main header 2 is a good practice, although it takes a 1 little extra work.
If you would work with Eclipse CDT you could 4 try out http://includator.com to optimize your include structure. However, Includator 3 might not know enough about VC++'s predefined 2 includes and setting up CDT to use VC++ with 1 correct includes is not built into CDT yet.
The latest Jetbrains IDE, CLion, automatically 5 shows (in gray) the includes that are not 4 used in the current file.
It is also possible 3 to have the list of all the unused includes 2 (and also functions, methods, etc...) from 1 the IDE.
Some of the existing answers state that 9 it's hard. That's indeed true, because you 8 need a full compiler to detect the cases 7 in which a forward declaration would be 6 appropriate. You cant parse C++ without 5 knowing what the symbols mean; the grammar 4 is simply too ambiguous for that. You must 3 know whether a certain name names a class 2 (could be forward-declared) or a variable 1 (can't). Also, you need to be namespace-aware.
Maybe a little late, but I once found a 5 WebKit perl script that did just what you 4 wanted. It'll need some adapting I believe 3 (I'm not well versed in perl), but it should 2 do the trick:
(this is an old branch because 1 trunk doesn't have the file anymore)
If there's a particular header that you 26 think isn't needed anymore (say string.h), you 25 can comment out that include then put this 24 below all the includes:
#ifdef _STRING_H_
# error string.h is included indirectly
#endif
Of course your interface 23 headers might use a different #define convention to 22 record their inclusion in CPP memory. Or 21 no convention, in which case this approach 20 won't work.
Then rebuild. There are three 19 possibilities:
It builds ok. string.h wasn't 18 compile-critical, and the include for it can 17 be removed.
The #error trips. string.g was 16 included indirectly somehow You still don't 15 know if string.h is required. If it is 14 required, you should directly #include it 13 (see below).
You get some other compilation 12 error. string.h was needed and isn't being included 11 indirectly, so the include was correct to 10 begin with.
Note that depending on indirect 9 inclusion when your .h or .c directly uses another 8 .h is almost certainly a bug: you are in 7 effect promising that your code will only 6 require that header as long as some other 5 header you're using requires it, which probably 4 isn't what you meant.
The caveats mentioned 3 in other answers about headers that modify 2 behavior rather that declaring things which 1 cause build failures apply here as well.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.