|
|
It is often desirable to avoid recompiling a set of header files, especially when they introduce many lines of code and the primary source files that #include them are relatively small. The C++ compiler provides a mechanism for, in effect, taking a snapshot of the state of the compilation at a particular point and writing it to a disk file before completing the compilation; then, when recompiling the same source file or compiling another file with the same set of header files, it can recognize the ``snapshot point,'' verify that the corresponding precompiled header (``PCH'') file is reusable, and read it back in. Under the right circumstances, this can produce a dramatic improvement in compilation time; the trade-off is that PCH files can take a lot of disk space.
When -Rauto appears on the CC command line, automatic precompiled header processing is enabled. This means the front end will automatically look for a qualifying precompiled header file to read in and/or will create one for use on a subsequent compilation.
The PCH file will contain a snapshot of all the code preceding the ``header stop'' point. The header stop point is typically the first token in the primary source file that does not belong to a preprocessing directive, but it can also be specified directly by #pragma hdrstop (see below) if that comes first. For example:
#include "xxx.h" #include "yyy.h" int i;The header stop point is int (the first non-preprocessor token) and the PCH file will contain a snapshot reflecting the inclusion of xxx.h and yyy.h. If the first non-preprocessor token or the #pragma hdrstop appears within a #if block, the header stop point is the outermost enclosing #if. To illustrate, here's a more complicated example:
#include "xxx.h" #ifndef YYY_H #define YYY_H 1 #include "yyy.h" #endif #if TEST int i; #endifHere, the first token that does not belong to a preprocessing directive is again int, but the header stop point is the start of the #if block containing it. The PCH file will reflect the inclusion of xxx.h and conditionally the definition of YYY_H and inclusion of yyy.h; it will not contain the state produced by #if TEST.
A PCH file will be produced only if the header stop point and the code preceding it (mainly, the header files themselves) meet certain requirements:
// xxx.h class A {// xxx.C #include "xxx.h" int i; };
// yyy.h static// yyy.C #include "yyy.h" int i;
As an illustration, consider two source files:
// a.C #include "xxx.h" ... // Start of codeWhen a.C is compiled with CC -Rauto, a precompiled header file named a.pch is created. Then, when b.C is compiled (or when a.C is recompiled), the prefix section of a.pch is read in for comparison with the current source file. If the command line options are identical, if xxx.h has not been modified, and so forth, then, instead of opening xxx.h and processing it line by line, the front end reads in the rest of a.pch and thereby establishes the state for the rest of the compilation.// b.C #include "xxx.h" ... // Start of code
It may be that more than one PCH file is applicable to a given compilation. If so, the largest (i.e., the one representing the most preprocessing directives from the primary source file) is used. For instance, consider a primary source file that begins with
#include "xxx.h" #include "yyy.h" #include "zzz.h"If there is one PCH file for xxx.h and a second for xxx.h and yyy.h, the latter will be selected (assuming both are applicable to the current compilation). Moreover, after the PCH file for the first two headers is read in and the third is compiled, a new PCH file for all three headers may be created.
When a precompiled header file is created, it takes the name of the primary source file, with the suffix replaced by .pch. Unless -Rdir is specified (see below), it is created in the directory of the primary source file.
When the -v option to CC is used, a message such as
"test.C": creating precompiled header file "test.pch"is issued if a precompiled header file is created or used.
In automatic mode (i.e., when -Rauto is used) the front end will deem a precompiled header file obsolete and delete it under the following circumstances:
The CC command-line option -Rcreate=filename specifies that a precompiled header file of the specified name should be created. The CC command-line option -Ruse=filename specifies that the indicated precompiled header file should be used for this compilation; if it is invalid (i.e., if its prefix does not match the prefix for the current primary source file), a warning will be issued and the PCH file will not be used.
When either of these options is used in conjunction with -Rdir=directory-name, the indicated file name (which may be a path name) is tacked on to the directory name, unless the file name is an absolute path name.
The manual-mode PCH options may not be used in conjunction in automatic mode. In other words, these options are not compatible with -Rauto. Nevertheless, most of the description of automatic PCH processing applies to one or the other of these modes --- header stop points are determined the same way, PCH file applicability is determined the same way, and so forth.
There are several ways in which the user can control and/or tune how precompiled headers are created and used.
#include "xxx.h" #include "yyy.h" #pragma hdrstop #include "zzz.h"Here, the precompiled header file will include processing state for xxx.h and yyy.h but not zzz.h. (This is useful if the user decides that the information added by what follows the #pragma hdrstop does not justify the creation of another PCH file.)
The relative overhead incurred in writing out and reading back in a precompiled header file is quite small for reasonably large header files.
In general, it doesn't cost much to write a precompiled header file out even if it does not end up being used, and if it is used it almost always produces a significant speedup in compilation. The problem is that the precompiled header files can be quite large (from a minimum of about 250K bytes to several megabytes or more), and so one probably doesn't want many of them sitting around.
Thus, despite the faster recompilations, precompiled header processing is not likely to be justified for an arbitrary set of files with nonuniform initial sequences of preprocessing directives. Rather, the greatest benefit occurs when a number of source files can share the same PCH file. The more sharing, the less disk space is consumed. With sharing, the disadvantage of large precompiled header files can be minimized, without giving up the advantage of a significant speedup in compilation times.
Consequently, to take full advantage of header file precompilation, users should expect to reorder the #include sections of their source files and/or to group #include directives within a commonly used header file.
A common idiom is this:
#include "common_head.h" #pragma hdrstop #include ...where common_head.h pulls in, directly and indirectly, the header files used throughout all the source files that make up the program. The #pragma hdrstop is inserted to get better sharing with fewer PCH files. Another idiom, is to partition related header files into groups:
#include "common_head.h" #include "group1.h" #pragma hdrstop #include ...If disk space were at a premium, one could decide to make one header file that pulls in all the header files used --- then, a single PCH file could be used in building the whole program.
Different environments and different projects will have different needs, but in general, users should be aware that making the best use of the precompiled header support will require some experimentation and probably some minor changes to source code.