Skip to content

precompiled headers

They do not only exist for Microsoft CL, gcc has them as well.

Precompiling a header file is very much like compiling .c into .o You compile 1 .h file into 1 .h.pch file, under the hood that file can include x other header files, but the top is 1-1.

This was an attempt to get c++ compiling faster but turns out not te be the wonder cure. I got a speed improvement of around 20 % So for now, it is not really worth the effort. Still here are my findings.

tutorial

This example file :

boost example
#include <boost/xpressive/xpressive.hpp>
#include <iostream>

using namespace std;
using namespace boost.. code-block::xpressive;

//A simple regex test
int main()
{
    std.. code-block::string hello( "hello world!" );

    sregex rex = sregex.. code-block::compile( "(\w+) (\w+)!" );
    smatch what;
    if( regex_match( hello, what, rex ) )
    {
        std.. code-block::cout << what[0] << 'n'; // whole match
        std.. code-block::cout << what[1] << 'n'; // first capture
        std.. code-block::cout << what[2] << 'n'; // second capture
    }
    return 0;
}

It is small but you need libboost-dev installed to get it compiled. This is also part of the example since boost has a LOT of headers and is a perfect example for speed gain. If you compile it it takes about ten seconds:

compile slow
time g++ test.cpp

10 seconds is a very long wait in my opinion. So

Now let's see what headers are used in this compilation, g++ has the -H flag for that:

list used headers
g++ -H test.cpp

The list you get seems endless,so there must be some time to be saved there. Let's precompile the header file included int test.cpp

precompile the header
locate xpressive.hpp
sudo g++ /usr/include/boost/xpressive/xpressive.hpp

sudo is needed, because it will try to create /usr/include/boost/xpressive/xpressive.hpp.gch on that location. After this, if you run the example again with -H you will see :

list headers
g++ -H test.cpp 


! /usr/include/boost/xpressive/xpressive.hpp.gch
test.cpp
. /usr/include/c++/4.4/iostream
.. /usr/include/c++/4.4/x86_64-linux-gnu/bits/c++config.h
.. /usr/include/c++/4.4/ostream
.. /usr/include/c++/4.4/istream
test.cpp

The -H now lists the precompiled header instead, the ! means it was able to use it correctly, if not it will be an 'x'.

Timing the compilation again makes it 8 seconds. Not the immense improvement i hoped for, but still. ## scons

g++ is used, because let's face it, gcc is fast enough, but that also would work.G++ just looks for .h.gch first, and otherwise takes .h ! But beware !!, if you change the original header. You must either delete the gch file or recompile it !!

A simple BUILDER to generate the precompiled headers is implemented in the scons script for klopt web services, the major parts are :

scons
1
2
3
4
5
6
7
8
9
pcheaders= [ './app.h')]

if 'pch' in COMMAND_LINE_TARGETS:
    mycommand= '$CXX ' + env.subst('$CPPFLAGS') + ' $SOURCES -o $TARGET'
    myaction = Action(mycommand)
    pch= Builder(action=myaction)
    env = Environment(BUILDERS = {'Pch' : pch})
    env.Pch('app.h.gch', pcheaders, CFLAGS=env.subst('$CPPFLAGS'));
    env.Alias('pch','app.h.gch');

Ok this is a 3 stage rocket, maybe it can be done shorter but i remain a non-scons expert.

  • create the command line you want to use as a python string
  • create an scons Action from that string
  • create a scons Builder using that action