I’ve seen a few people assert the precompiled headers are a pain in the butt, or not workable for large scale projects. In fact, it’s incredibly easy to add precompiled headers to a GCC-based project, and it can be quite beneficial.
Since I’m mostly familiar with Makefiles, I’ll present an example here that uses Make. It trivially extends to other similar build systems such as SCons, NMake, or Ant, but I’m not so sure about Visual studio projects. This example builds a single static library and several test applications. I’ve stripped out most of my compiler flags for brevity.
# boilerplate settings... SHELL = /bin/bash CXX = g++ -c CXXFLAGS += -std=c++98 -pedantic -MMD -g -Wall -Wextra LD = g++ LDFLAGS += -rdynamic -fno-stack-protector AR = ar # generic build rules # $@ is the target, $< is the first source, $^ is all sources define compile $(CXX) -o $@ $< $(CXXFLAGS) endef define link $(LD) -o $@ $(filter %.o,$^) $(filter %.a,$^) $(LDFLAGS) endef define ar $(AR) qsc $@ $(filter %.o,$^) endef # all library code is in src/ # all test applications are single-source # e.g. testfoo is produced from from testfoo.cxx and libsseray.a TEST_SRC = $(wildcard test*.cxx) LIB_SRC = $(wildcard src/*.cxx) TESTS = $(basename $(TEST_SRC)) LIB = libsseray.a all : $(TESTS) $(TESTS) : $(LIB) $(TESTS) : % : %.o $(link) %.o : %.cxx $(compile) $(LIB) : $(LIB_SRC:cxx=o) $(ar) # gcc-provided #include dependencies -include $(TEST_SRC:cxx=d) $(LIB_SRC:cxx=d) clean : rm -f $(LIB) $(TESTS) $$(find . -name '*.o' -o -name '*.d')
In order to use a precompiled header, this is what needs to be added to the Makefile. There are no source code modifications at all. I created a file pre.h that includes all of the system C and C++ headers that I use (in particular <iostream> is a big expense for the compiler).
# PCH is built just like all other source files # CXXFLAGS must match everything else pre.h.gch : pre.h $(compile) # all object files depend on the PCH for build ordering $(TEST_SRC:cxx=o) $(LIB_SRC:cxx=o) : pre.h.gch # this is equivalent to adding '#include <pre.h>' to the top of every source file $(TEST_SRC:cxx=o) $(LIB_SRC:cxx=o) : CXXFLAGS += -include pre.h # pre.h.gch should be cleaned up along with everything else clean : rm -f (...) pre.h.gch
The project itself is fairly small—16 source files totaling 1800 SLOC—but this small change just decreased my total build time from 12 to 8 seconds. This is entirely non-intrusive to the code, so adding it is a one-time cost (as opposed to the Microsoft stdafx.h approach, which is O(N) cost in the number of source files). It is also easy to disable for production builds, if you only want to use the PCH machinery for your day-to-day edit-compile-test cycle.

Leave a comment
Comments feed for this article