105

How can I get precompiled headers working with GCC?

I have had no luck in my attempts and I haven't seen many good examples for how to set it up. I've tried on Cygwin GCC 3.4.4 and using 4.0 on Ubuntu.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lee Baldwin
  • 1,560
  • 2
  • 12
  • 10
  • I tried it and i had the optimal use case for precompiled headers because my c source is compiler generated and not user written. Sun Studio and especially Visual Studio improved the build time a lot. On gcc it was getting even worse then without precompiled headers. This was with 3.4 haven't testet with 4.x but speed and gcc is mutually exclusive. – Lothar Nov 04 '09 at 12:33
  • @Lothar what was the code? I find g++ about 10x faster than the recent Visual Studio compilers, on some heavily templated code. – the swine Oct 08 '14 at 15:30
  • I'm not using templates in my C++ code. It's just C + exception handling + nice C++ extensions. Even now 6 years after this question VS2010 is a magnitude faster. But in the meantime i have 16 cores so i can live with it. – Lothar Nov 09 '14 at 05:24

7 Answers7

64

I have definitely had success. First, I used the following code:

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

using namespace std;
using namespace boost::xpressive;

// A simple regular expression test
int main()
{
    std::string hello("Hello, World!");

    sregex rex = sregex::compile( "(\\w+) (\\w+)!" );
    smatch what;

    if( regex_match( hello, what, rex ) )
    {
        std::cout << what[0] << '\n'; // Whole match
        std::cout << what[1] << '\n'; // First capture
        std::cout << what[2] << '\n'; // Second capture
    }
    return 0;
}

This was just a Hello, World! program from Boost Xpressive. First, I compiled with the -H option in GCC. It showed an enormous list of headers that it used. Then, I took a look at the compile flags my IDE (Code::Blocks) was producing and saw something like this:

g++ -Wall -fexceptions  -g  -c main.cpp -o obj/Debug/main.o

So I wrote a command to compile the Xpressive.hpp file with the exact same flags:

sudo g++ -Wall -fexceptions  -g /usr/local/include/boost/xpressive/xpressive.hpp

I compiled the original code again with the -H and got this output:

g++ -Wall -fexceptions -H  -g     -c main.cpp -o obj/Debug/main.o

! /usr/local/include/boost/xpressive/xpressive.hpp.gch
main.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
main.cpp

The ! means that the compiler was able to use the precompiled header. An x means it was not able to use it. Using the appropriate compiler flags is crucial. I took off the -H and ran some speed tests. The precompiled header had an improvement from 14 seconds to 11 seconds. Not bad, but not great.

Note: Here's the example. I couldn't get it to work in the post.

BTW: I'm using the following g++:

g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
User1
  • 39,458
  • 69
  • 187
  • 265
  • 24
    Adding -Winvalid-pch will help you debug if and why anything goes wrong in the usage of the PCH. – lefticus Jan 13 '12 at 14:40
  • "not bad but not great" precompiled headers are useful when you have many many headers which relink each other, so they will reduce compile time on very big project which use big libraries or many libraries. – jokoon Sep 28 '13 at 18:15
  • 4
    "not bad but not great": using gcc 4.4.7, 136 .cpp files 35.5 Mb total size, 148 .h files 5.5 Mb total size, the .gch file is 48 Mb, Debug build takes 2'20" (vs 2'14" non-pch), -O2 optimized build takes 4'30" (vs 5'33" non-pch) The effect would be expected near debug builds, but it's just the optimized build which profits from precompiling.... Not sure why. Precompiling is way more dramatic on Windows! – Andreas Vergison Apr 23 '14 at 13:45
  • 1
    (cont'd) Corresponding pch/non-pch output files have exactly same size byte size, that's good. The above timings seem to vary when repeating the builds, for instance -O2 non-pch varies between 3'45" and 5'33", so it's not exact science, perhaps due to running in VMware. Anyway, gcc pch doesn't look beneficial at all in my case. Compare it to the same code base on Windows VS2012 (x64, single threaded compile): debug 46" pch, 2'50" non-pch, release 2'13" pch, 5'02" non-pch. And of course even much faster when enabling multi-processor... – Andreas Vergison Apr 23 '14 at 14:27
  • @AndreasVergison - Have you tried using `-Winvalid-pch` to make sure that the precompiled header is being properly used? We notice a big improvement using pch for our debug builds, so I wonder if there's a problem with your setup. – Josh Kelley Sep 12 '14 at 12:58
  • The same flags are applicable to Clang on mac if anyone is using it. Thanks for this answer, it helped me a lot. – Sri Harsha Chilakapati Nov 12 '14 at 08:34
58

Firstly, see the documentation here.

You compile headers just like any other file but you put the output inside a file with a suffix of .gch.

So for example if you precompile stdafx.h you will have a precompiled header that will be automatically searched for called stdafx.h.gch anytime you include stdafx.h

Example:

stdafx.h:

#include <string>
#include <stdio.h>

a.cpp:

#include "stdafx.h"
int main(int argc, char**argv)
{
  std::string s = "Hi";
  return 0;
}

Then compile as:

> g++ -c stdafx.h -o stdafx.h.gch
> g++ a.cpp
> ./a.out

Your compilation will work even if you remove stdafx.h after step 1.

Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
10

The -x specifier for C++ precompiled headers is -x c++-header, not -x c++. Example usage of PCH follows.

pch.h:

// Put your common include files here: Boost, STL as well as your project's headers.

main.cpp:

#include "pch.h"
// Use the PCH here.

Generate the PCH like this:

$ g++ -x c++-header -o pch.h.gch -c pch.h

The pch.h.gch must be in the same directory as the pch.h in order to be used, so make sure that you execute the above command from the directory where pch.h is.

Kotauskas
  • 1,239
  • 11
  • 31
psaghelyi
  • 500
  • 4
  • 12
9

Call GCC the same way as if you call it for your source file, but with a header file.

E.g.,

g++ $(CPPFLAGS) test.h

This generates a file called test.h.gch.

Every time GCC searches for test.h, it looks first for test.h.gch and if it finds it it uses it automatically.

More information can be found under GCC Precompiled Headers.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
simon
  • 153
  • 2
  • 7
  • I'm using gcc 3.4 and the line g++ stdafx.h will not compile, you get error "g++: compilation of header file requested", but this will compile, not sure if that's what I want though: "g++ -c -x c++ stdafx.h -o stdafx.h.pch" – stefanB May 15 '09 at 01:56
8

I have managed to get precompiled headers working under gcc once in the past, and I recall having problems then as well. The thing to remember is that gcc will ignore the file (header.h.gch or similar) if certain conditions are not met, a list of which can be found on the gcc precompiled header documentation page.

Generally it's safest to have your build system compile the .gch file as a first step, with the same command line options and executable as the rest of your source. This ensures the file is up to date and that there are no subtle differences.

It's probably also a good idea to get it working with a contrived example first, just to remove the possibility that your problems are specific to source code in your project.

Paul
  • 151
  • 2
3

Make sure to -include your_header.h

This is how I precompiled and used bits/stdc++.h collection.

Code

#include <bits/stdc++.h>

Then I located the lib by compiling my file with -H and looking at output

g++ sol.cpp -H -O3 -pthread -lm -std=c++14 -o executable

where I saw

. /usr/include/x86_64-linux-gnu/c++/7/bits/stdc++.h

So I made a new directory bits inside of current one and copied stdc++.h from there.

Then I ran

g++ bits/stdc++.h -O3 -std=c++14  -pthread

which generated bits/stdc++.gch

Normally I compiled my code via

g++ sol.cpp -O3 -pthread -lm -std=c++14 -o executable

, but I had to modify that to

g++ sol.cpp -include bits/stdc++.h -O3 -pthread -lm -std=c++14 -o executable

as it only resolved to .gch file instead of .h with -include bits/stdc++.h That was key for me. Other thing to keep in mind is that you have to compile *.h header file with almost the same parameters as you compile your *.cpp. When I didn't include -O3 or -pthread it ignored the *.gch precompiled header.

To check if everything's correct you can measure time difference via comparing result of

time g++ sol.cpp ...

or run

g++ sol.cpp -H -O3 -pthread -lm -std=c++14 -o executable

again and look for header paths and if you now get ! before library path, for example

! ./bits/stdc++.h.gch
....
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Íhor Mé
  • 896
  • 9
  • 13
0

A subtle tip about the file extension that tripped me up, because I wasn't paying close enough attention: the .gch extension is added to the precompiled file's full name; it doesn't replace .h. If you get it wrong, the compiler won't find it and silently does not work.

precomp.h => precomp.h.gch

Not:

precomp.h => precomp.gch

Use GCC's -H to check if it's finding/using it.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brad Robinson
  • 44,114
  • 19
  • 59
  • 88