I use gcc (running as g++
) and GNU make.
I use gcc to precompile a header file precompiled.h
, creating precompiled.h.gch
; the following line in a Makefile does it:
# MYCCFLAGS is a list of command-line parameters, e.g. -g -O2 -DNDEBUG
precompiled.h.gch: precompiled.h
g++ $(MYCCFLAGS) -c $< -o $@
All was well until i had to run g++
with different command-line parameters.
In this case, even though precompiled.h.gch
exists, it cannot be used, and the compilation will be much slower.
In the gcc documentation i have read that to handle this situation,
i have to make a directory called precompiled.h.gch
and put
the precompiled header files there,
one file for each set of g++
command-line parameters.
So now i wonder how i should change my Makefile to tell g++
to create
the gch-files this way.
Maybe i can run g++
just to test whether it can use any existing file
in the precompiled.h.gch
directory,
and if not, generate a new precompiled header with a unique file name.
Does gcc have support for doing such a test?
Maybe i can implement what i want in another way?
It seems weird to answer my own question; anyway, here goes.
To detect whether a suitable precompiled header file exists, i add a deliberate error to my header file:
// precompiled.h
#include <iostream>
#include <vector>
...
#error Precompiled header file not found
This works because if gcc finds a precompiled header, it will not read the .h
file, and will not encounter the error.
To "compile" such a file, i remove the error first, placing the result in a temporary file:
grep -v '#error' precompiled.h > precompiled.h.h
g++ -c -x c++ $(MYCCFLAGS) precompiled.h.h -o MORE_HACKERY
Here MORE_HACKERY is not just a plain file name, but contains some code to make a file with unique name (mktemp
). It was omitted for clarity.
There is a simpler way than introducing an #error in precompiled.h: never create this file at all. Neither G++ nor Visual C++ (at least up to 2005) expect the "real" file to be there, if a precompiled version is around (and if they get the necessary compilation flags).
Let's say the list of #includes that we want to precompile is called "to_be_precompiled.cpp". The filename extension doesn't matter much, but I don't like to call this a .h file, since it has to be used in a way different from genuine header files, and it's easier in Visual C++ if this is a .cpp. Then pick a different name to refer to it throughout the code, let's say "precompiled_stuff". Again, I I don't like to call this a .h file, because it's not a file at all, it's a name to refer to precompiled data.
Then in all other source files, the statement #include "precompiled_stuff"
is not a genuine include, but simply loads precompiled data. It's up to you to prepare the precompiled data.
- For g++, you need a build rule to create "precompiled_stuff.gch" from a source file whose name doesn't matter to the compiler (but would be "to_be_precompiled.cpp" here).
- In Visual C++, the string "precompiled_stuff" equals the value of the /Yu flag and the precompiled data loaded comes from a .pch file with an unrelated name, that you also created from an unrelated source file (again "to_be_precompiled.cpp" here).
- Only when building with a compiler without precompiled header support, a build rule needs to generate an actual file called "precompiled_stuff", preferably in the build directory away from the real source files. "precompiled_stuff" is either a copy of "to_be_precompiled.cpp", a hard or symbolic link, or a small file containing
#include "to_be_precompiled.cpp"
.
In other words, you take the viewpoint that every compiler supports precompilation, but it's just a dumb copy for some compilers.