Using precompiled headers in C
By dpagan on Feb 28, 2006
Beginning with version 5.5, the Sun C compiler has provided a facility for manually precompiling header files. Beginning with version 5.6, this feature was expanded to include automatic creation and use of precompiled headers, making this already helpful feature even more easy to use. Here's some additional information about precompiled headers which should help clarify what this feature really is and show how it can best be utilized. With a bit of experimentation, the benefits of this feature should more than compensate for the time invested in initial setup.
Precompiled header (PCH) files can reduce compilation time by eliminating recompilation of one or more header files for each source file recompiled. A PCH file is, in essence, a snapshot of a compilation at a particular point in time. With this information, the compiler can place itself back into the same state of compilation as when the PCH file was first created. In many cases, it is much quicker to do this using a single PCH file than it is to recompile using all the headers from which the PCH file was originally created.
Note that using a precompiled headers isn't always beneficial. There is overhead involved in both creating and using a precompiled header. To gain significantly by using precompiled headers, there must be something inherent in the included file(s) that when "precompiled" allows compilation to proceed faster. For example, programs typically contain includes of system header files and other user include files that further expand into other includes. These includes often contain such things as type and variable declarations, conditionally compiled code, additional includes, and macro definitions. Some of these include files may even be included multiple times, such that the compiler ends up scanning an entire file only to find that it contains nothing but redundant includes or macro definitions. A precompiled header file can, under these conditions, markedly reduce recompilation time. This is possible because:
- only one file is opened to read the header file contents ("source") derived from many other include files;
- types and variables are recognized without the need for recompilation;
- macros are already expanded.
Sun PCH files are created either manually or automatically. In general, to benefit from manual PCH, there should be some knowledge of the existing code base and a willingness to analyze it for opportunities to improve the efficacy of PCH. To maximize the benefit of manual PCH, then, the first step is to analyze the source files and make any necessary changes. Here is a list of source file and header file attributes that can affect the potential gain from manual PCH:
- Look for commonality in header file inclusion. Does it exist already? Can it be used as is to create an effective PCH file?
a.c b.c c.c
#include "a.h" #include "a.h" #include "a.h"
#include "b.h" #include "b.h" #include "b.h"
. #include "c.h" #include "d.h"
. . #include "c.h"
. . .
. . .
it is clear that include files "a.h" and "b.h" are common to all three
examples and can be used to create a PCH file. This PCH file can in
turn be used in subsequent recompilations of any of the above
three sources to speed up the compile time.
- Look for commonality that can be achieved by reordering existing includes.
that we know that we can safely move the include of "c.h" prior to
the include of "d.h", the file "c.c" could be edited and the positions
of the includes of "d.h" and "c.h" reversed. A PCH file containing
the contents of "a.h", "b.h", and "c.h" (and any other include files
included) could then be created and used for any subsequent
recompilations of "b.c" and "c.c"
- Remove illegal elements from the viable source prefix, if possible, such as definitions (see the C User's Guide for more examples of what invalidates a viable source prefix).
- Move pre-processor directives, if possible, such that they won't
potentially cause conflicts with other source files.
#define FOO 1
If the define of FOO is unnecessary prior to the include of "b.h", it
could be moved past the last include so that there will be no
possibility that it may clash with the viable source prefix of another
Automatic PCH, while simpler to use, isn't necessarily the PCH mode of choice. While it does provide an intuitively easier approach to using precompiled headers, beyond that it still requires a program to have the same basic elements as noted above for manual PCH in order to truly be effective:
- commonality of header file inclusion, both in number and order, among a large number of source files;
- relatively large number of includes, either in the source or nested within other includes;
- numerous declarations and macro definitions;
- stability of header files involved in the PCH file
One last feature of automatic PCH which can prove to be very useful is the variant specified simply as -xpch=autofirst. This tells the compiler to attempt to create a precompiled header automatically using only the contents of the first header file (which can, of course, include an arbitrary number of other header files). This simple form of automatic precompiled headers can, under the right circumstances, provide a dramatic reduction in compile time. The main requirement for "autofirst" to be effective is that the first header file included should be relatively large with respect to the main source file and/or it should include other large header files.