Why Use Precompiled Headers (C/C++)

Why use precompiled headers (C/C++)?

It compiles a lot quicker. C++ compilation takes years without them. Try comparing some time in a large project!

What is pch.h and why is it needed to be included as the first header file?

pch stands for precompiled header.

In computer programming, a precompiled header is a (C or C++) header file that is compiled into an intermediate form that is faster to process for the compiler. 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.

To reduce compilation times, some compilers allow header files to be compiled into a form that is faster for the compiler to process. This intermediate form is known as a precompiled header, and is commonly held in a file named with the extension .pch or similar, such as .gch under the GNU Compiler Collection.

In Visual Studio, precompiled header is usually named "pch.h" (for console based applications), but it is possible to use different name, or not use it at all. Which file would be precompiled header, if any, is determined by projects settings.

If the precompiled header file is "pch.h" and the compile option is /Yu, Visual Studio will not compile anything before the #include "pch.h" in the source file; it assumes all code in the source up to and including that line is already compiled.

Definition of C++ precompiled Headers

Precompiled headers (PCH for short) are something that the some compilers support. The support and what they contain [aside from "something that hopefully can be read quicker than the original header file"] is up to each compiler producer to decide. I have a little bit of understanding of how Clang does it's precompiled headers, and it's basically a binary form of the "parsed" C or C++ code in the header - so it produces a single file that doesn't need parsing [to the same level as the header file itself].

The purpose is to reduce the compile-time. However, in my experience, the LONG part of the compilation is typically code-generation with optimisation. However, in some instances, especially when LOTS of header-files are involved, the time to read and parse the header files can be a noticeable part of the overall compilation time.

Generally speaking, how they are used is that you tell the compiler that you want precompiled header, and for each compilation, the compiler will generate the precompiled header if it's not already there, and read it in when it is present [1] - commonly this is done for one named header file, which includes lots of other things. Microsoft Visual Studio typically has a file called "stdafx.h" that is precompiled - and at least in the case of MS products, this has to be the first file that is inclduded in a project [this is so that no other header file for example changes the meaning of some macro - I expect there is a hash of the compiler/command-line definitions of macros, so if one of those changes, the PCH is recompiled].

The idea is not to include every single header-file in this one precompiled file, but header files that are used in MOST files, and that are not changing often (the PCH needs to be regenerated if one if the files that is precompiled has changed, so it's no point in doing that if you keep changing the header-files frequently). Of course, like any other build dependency, anything using the precompiled header will need to be rebuilt if the PCH has changed.

For exactly how to use this, you will need to read the documentation for the compiler you are using.

[1] If nothing has changed that requires it to be rebuilt.

How precompiled headers actually works

I have no particular knowledge of VC++'s innards. However, having some knowledge of compiler design and theory, what these so-called "precompiled headers" are can't be anything more than just the result of the initial lexical analysis and tokenization phases of a classical compiler design.

Consider a simple header file that contains the following:

#ifdef FOO
#define BAR 10
#else
#undef FOOBAR
class Foo {
public:
void bar();
};
#include "foobar.h"
#endif

You have to understand that the effect of using a so-called "pre-compiled" header must be identical to using the header file, as is.

Here, you don't really know what this header file is going to do. It all depends on what preprocessor macros are defined when the header file is actually included. You don't know which macros this header file will define. You don't know which macros this header file will undefine. You don't know what other header files this header file will include. You don't really know a lot, here.

The only thing you can conceptually do, to "precompile" a header file, is to pre-parse it. Convert the individual elements of the language, the individual keywords -- like "#ifdef", "class", and all others, into individual binary tokens. Remove any comments, whitespace, etc...

The first phase of compiling a traditional language involves parsing the plain text source into the internal language elements. The lexical analysis and the tokenization phase. After the individual language elements get parsed, then an attempt is made to figure out how the resulting, parsed source code, should get turned into an object module. And that's where 99% of the compiler's work is. The initial lexical analysis phase is not really a lot, but that's pretty much all you can do to "precompile" the source code, and save the internal binary representation of the tokenized source, so that this phase can be skipped, when actual code that uses the "precompiled" source is compiled.

I am assuming that VC++ places little, if no restrictions at all, on the contents of precompiled headers. However, if there are some restrictions -- say, the precompiled headers cannot have any conditional preprocessor directives (ifdef/ifndef) except for the classical guards -- than it would be possible to do more work to produce the precompiled headers, and save a little bit more work, here. Other restrictions on the contents of precompiled headers could also result in some additional functionality being shifted into the precompilation phase.

What are the pros & cons of pre-compiled headers specifically in a GNU/Linux environment/tool-chain?

The only potential benefit to precompiled headers is that if your builds are too slow, precompiled headers might speed them up. Potential cons:

  • More Makefile dependencies to get right; if they are wrong, you build the wrong thing fast. Not good.

  • In principle, not every header can be precompiled. (Think about putting some #define's before a #include.) So which cases does gcc actually get right? How much do you want to trust this bleeding edge feature.

If your builds are fast enough, there is no reason to use precompiled headers. If your builds are too slow, I'd consider

  • Buying faster hardware, which is cheap compared to salaries

  • Using a tool like AT&T nmake or like ccache (Dirk is right on), both of which use trustworthy techniques to avoid recompilations.

c++ precompiled headers vs. modules

An advantage of modules is that they are a standard feature. All C++20 compilers must implement them as described in the language. Precompiled headers are not a standard feature. Not all compilers necessarily have that feature, and each compiler that has, implements them in their own way that isn't necessarily compatible with other compilers.

An advantage of modules over headers is that they encapsulate macros. A (rarely useful) advantage of headers is that they can "export" macros.

An advantage of modules over headers is that you have explicit control over what names you export, which allows encapsulating implementation details.

At the moment of writing, a disadvantage of modules is that only MSVC has fully implemented them so far.



Related Topics



Leave a reply



Submit