After reading this nice article (The Care and Feeding of Pre-Compiled Headers), I have some doubts regarding how these can actually work in real life. More specifically, how can I know that I need to trigger the rebuild of the pre-compiled header in the following scenarios:
#define
something in one of my .cpp files that alters the way the pre-processor interprets some headers that are already included in my pre-compiled header#define
s a specific pre-processor directive that alters the way the pre-processor interprets a header already included in the precompiled header#include
other headersShould the usage of pre-compiled headers enforce a certain restrictive coding style like limiting the number of headers included in .cpp files to one and never #define
ing stuff in a .cpp file?
While Microsoft's compiler probably does a decent job with pre-compiled headers (by applying some MS-specific voodoo) because, as far as I know, it provides the /Yc
and /Yu
options that are supposed to do all the plumbing, for GCC it seems that this functionality requires a lot of manual work and creativity in the Makefile and I wasn't able to find a template that is supposed to address all the pitfalls of using pre-compiled headers.
For example, if I have a project which builds several libraries, in order not to rebuild all of them after each change, I have to use some really cute sed
tricks in the Makefile to detect if one of the headers #include
d by the current library was modified (or it #include
s a modified header). I fear to even think of the complications that pre-built headers would actually imply in order for the build script to rebuild them each time it is necessary.
Precompiled headers (PCH) are a performance feature supported by some compilers to compile a stable body of code, and store the compiled state of the code in a binary file. During subsequent compilations, the compiler will load the stored state, and continue compiling the specified file.
Usage of precompiled headers may significantly reduce compilation time, especially when applied to large header files, header files that include many other header files, or header files that are included in many translation units.
The precompiled header is compiled only when it, or any files it includes, are modified. If you only make changes in your project source code, the build will skip compilation for the precompiled header. The compiler options for precompiled headers are /Y .
To make builds faster, GCC allows users to `precompile' a header file; then, if builds can use the precompiled header file they will be much faster. To create a precompiled header file, simply compile it as you would any other file, if necessary using the -x option to make the driver treat it as a C or C++ header file.
Current GCC (i.e. 4.7) and previous versions of it works nicely with precompiled headers only when you have a single common header to your application, and when that single header (which includes in turn all the system ones, and the library specific ones, required by the application) is #include
-d (as the first non-comment lexeme of your sources) by every source of your application.
So you should have a single yourapp.h
and have every source file (i.e. every compilation unit) of yourapp
starting with #include "yourapp.h"
with the same preprocessing options (i.e. -D
or -I
or -U
) on the command line. That youapp.h
header file is usually #include
-ing many others, e.g. system headers (or GTK or Qt ones) like <stdlib.h>
or <sys/poll.h>
or [in C++] <algorithm>
or <gtk/gtk.h>
or <QtGui>
etc.
Recall that -H
is a useful option to get gcc
tell you what is included.
Your source files might have some additional #include
after #include "yourapp.h"
if so wanted.
After a [single] precompiled header has been included by GCC, you may of course #define
macros, #include
some non-precompiled header, do conditional compilation with #ifdef
, etc. But that preprocessing won't be "pre-compiled"!
This may not fit your needs or habits.
Some people (notably from Google, notably Diego Novillo) are working on the PreParsed Header (pph) branch to improve the situation, but the current GCC trunk has not got that work yet.
The explanation about that behavior of GCC is that a preprocessed header is essentially a persistent serialized checkpoint of the entire GCC heap (related to memory management inside GCC thru Ggc and GTY and gengtype
). That checkpointed heap can be loaded only when gcc
is in its initial empty state. As soon as something is known to gcc
(actually cc1
or cc1plus
) it cannot load any more any precompiled header file *.h.gch
and will revert to parsing the textual header file *.h
.
Even GCC 4.9 wants a single precompiled header. The pre-parsed header effort by Diego Novillo et al. has been abandoned.
Future versions (post C++14) of the C++ standard might define a module mechanism. See e.g. n4047 proposal and the C++20 standard.
(additional addenda, summer 2020) This still holds for GCC-10 where several static analyzer options exist. See also the Clang static analyzer and this draft report. Consider using Frama-C.
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