2
votes

The usual approach is to have one precompiled header in a project that contains the most common includes.

The problem is, that it is either too small or two big. When it is too small, it doesn't cover all the used headers so these have to be processed over and over in every module. When it is too large, it slows down the compilation too much for two reasons:

  1. The project needs to be recompiled too often when you change something in header contained in the precompiled header.
  2. The precompiled header is too large, so including it in every file actually slows down compilation.

What if I made all of the header files in a project precompiled. This would add some additional compiler work to precompile them, but then it would work very nicely, as no header would have to be processed twice (even preparing the precompiled header would use precompiled headers recursively), no extra stuff would have to be put into modules and only modules that are actually needed to be recompiled would be recompiled. In other words, for extra work O(N) complexity I would (theoretically) optimise O(n^2) comlexity of C++ includes. The precosseor to O(N), the processing of precompiled data would still be O(N^2), but at least minimised.

Did anyone tried this? Can it boost compile times in real life scenarios?

2
It fails on templates. You cannot precompile <vector> for example, because you don't know what T will be. You can precompile it with a bunch of types, but which ones? I would expect that every non-trivial header #includes some STL header, making this approach not feasible.nwp
You can precompile vector. The textual include file will be processed and prepared in the internal binary format for the compiler to be used later. The templates obviously need to be compiled again, but at least the file doesn't need to be preprocessed again.kovarex
Then what would be the advantage? I don't think the internal binary format will be significantly faster to process than the header itself, and the expensive optimization steps still have to be redone. Also you don't remove the redundant recompilation of headers for the same types.nwp
Including every .h file in every TU is very unlikely to be productive. Not just because of the namespace pollution, every minor change is going the recompile everything. Precompiled headers are useful when you have large headers that very rarely or never change. Like those of an operating system, a framework, a utility library.Hans Passant

2 Answers

2
votes

With GCC, the reliable way to use precompiled headers is to have one single (big) header (which #include-s many standard headers ...), and perhaps include some small header after the precompiled one.

See this answer for a more detailed explanation (for GCC specifically).

2
votes

My own experience with GCC and Clang with precompiled headers is that you only can give a single pre-compiled header per compilation. See also the GCC documentation, I quote:

A precompiled header file can be used only when these conditions apply:

  • Only one precompiled header can be used in a particular compilation.
  • ...

In practice, it's possible to compile every header to a precompiled header. (Recommended if you want to verify if everything is included, not recommended if you want to speed up compilation)

Based on your code, you can decide to use a different precompiled header based on the code that needs to be compiled. However, in general, it's a balancing act between compile time of the headers, compile-time of the CPP files and maintenance.

Adding a simple precompiled header that already contains several standard headers like string, vector, map, utility ... can already speed up your compilation with a remarkable percentage. (A long time ago, I've noticed a 15-20% on a small project)

The main gain you get from precompiled headers is that it:

  • only have to read 1 file instead of more, which improves on disk access
  • reads a binary format that's optimized for reading instead of plain text
  • it doesn't need to do all of the error checking as this was already done on creation

Even if you add a few headers that you don't use everywhere, it can still be much faster.

Lately, I also found the Clang build analyzer, it ain't ideal for big projects (see issue on github), though, it can give you some insights on where the time is being spent and what it can improve. (Or what you can improve in the codebase)

In all fairness, I don't use precompiled headers at this point in time. However, I do want to see it enabled on the project I'm working on.

Some other interesting reads: