1
votes

All my quetions are related to vc++ compiler but I guess other c++ compilers have the same behavior.

  1. Are the precompiled headers a preprocessor-related stuff or this is all about the compilation process? Or both? I have several guess:
    • PCH-engine only expands MACRO-definitions and nested headers and translates them into binary format (pch file). In this case all source-files (I mean cpp/hpp which may be included in PCH too) will being recompiled in EVERY source files in project. Or not?
    • All source-files will be compiled only once and pulled into single obj-file? For example, how many times will be compiled variant library in this example? I.e. only once - in PCH or two times - not in PCH but in both *.cpp files or three times - in PCH and both *.cpp files? and why?

//stdafx.h
#include <boost/variant/variant.hpp>

//test1.cpp
#include "stdafx.h"
#include <boost/variant/variant.hpp>
...

//test2.cpp
#include "stdafx.h"
...
  1. What files should I put in precompiled headers? I guess this is something that used everywhere in project and changed very rarely. What about libraries, boost for example? We use boost only in few source-files, should we put it in PCH?
3
Pre-compiled headers are more or less what it sounds like. It's all the headers included in the "stdafx.h" file, preprocessed, parsed and stored as a parse-tree (if you don't know what that is, read some compiler theory). That means when you include such a file, the compiler doesn't have to do all those steps for the header files, and the compilation will be quicker. The Boost header files are good candidates for inclusion in the PCH, as are really any external (and maybe even some internal) library headers.Some programmer dude
There's this document about clang PCH internals.Dan Mašek

3 Answers

6
votes

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.

1
votes

The precompiled header file, which gets compiled due to stdafx.cpp is stdafx.h. A developer would put rarely changed, and frequently needed header files and symbols in this header. Such as Windows.h, vector and some global macros and symbols. By frequently used, I mean across all files in given project.

What's the purpose and helpfulness of such file (PCH)? Well, VC++ compiler will compile entire stdafx.h file, recursively, all headers included all macros and other symbols. For first time, it will take a lot of time, and will produce a PCH file (hence pre-compiled header). On subsequent builds, the elements included through stdafx.h will not be recompiled (as they are already in some binary/pre-compiled format). This reduces build time, and it would vary depending how many elements (headers, symbols etc.) are put through stdafx.h file.

If you have a large codebase, and less of elements in stdafx, you wont get advantage (for example, including common Windows and STL headers everywhere, having externs and typedefs everywhere). Better you find those elements, and put them into stdafx.h, and remove them from header/CPP files. This will greatly reduce overall build times.

This is where you can change it: enter image description here

0
votes

I think that MSVC looks for <application_name>.pch for the sole precompiled header for the translation unit and uses that instead of the transcluded header included under #line 1 "c:\\application_name\\stdafx.h" in the preprocessed .i file, if it is available. The precompiled header is probably a serialised AST i.e. the header has been lexed and parsed into an AST representation. It then does not need to lex (or parse) this region of the preprocessed output and just uses the .pch, which contains the lex+parse output of what is written in the preprocessor output under stdafx.h. The preprocessor has already done all other work on stafx.h, such as expanding macros (which don't appear in the .i file / preprocessor output).