Search code examples
c++gccmakefileprecompiled-headers

Precompiled headers not used by GCC when building with a makefile


I'm trying to use precompiled headers with GCC to speed up the compilation process. If I launch the compilation directly from the command line the precompiled headers are used, but if I try to organize the compilation using a makefile they are not.

More specifically, I try to compile with GCC 8.1.0 a file main.cpp using a precompiled header lib.hpp.gch for the file lib.hpp included as first token in main.cpp.

lib.hpp is precompiled with

$ g++ -O2 -H -Wall -std=c++17 -c lib.hpp

main.cpp is then compiled with

$ g++ -O2 -H -Wall -std=c++17 -c main.cpp -o main.o
! lib.hpp.gch
...

and I can see from the "!" that the precompiled lib.hpp.gch is actually used.

If I write a makefile for this

CXX = g++
CXXFLAGS = -O2 -H -Wall -std=c++17

main.o: \
    main.cpp \
    main.hpp \
    lib.hpp
    $(CXX) $(CXXFLAGS) \
    -c main.cpp \
    -o main.o

and then use make, I would expect the same usage of the precompiled header

but instead it fails, as can be seen from the "x":

$ make
g++ -O2 -H -Wall -std=c++17 \
    -c main.cpp \
    -o main.o
x lib.hpp.gch
...

This is very strange, because the command issued by make seems exactly the same as the one that I used manually before.

I've also made measurement of timings and can confirm that the compilation via make is definitely slower than the manual one, confirming that the precompiled header is not used.

What's wrong in the makefile?


Solution

  • You're not including the PCH anywhere in your make command. Try this:

    CXX = g++
    CXXFLAGS = -O2 -H -Wall -std=c++17
    OBJ = main.o #more objects here eventually I would think!
    
    PCH_SRC = lib.hpp
    PCH_HEADERS = headersthataregoinginyourpch.hpp andanother.hpp
    PCH_OUT = lib.hpp.gch
    
    main: $(OBJ) 
         $(CXX) $(CXXFLAGS) -o $@ $^
    
    # Compiles your PCH
    $(PCH_OUT): $(PCH_SRC) $(PCH_HEADERS)
         $(CXX) $(CXXFLAGS) -o $@ $<
    
    # the -include flag instructs the compiler to act as if lib.hpp
    # were the first header in every source file
    %.o: %.cpp $(PCH_OUT)
        $(CXX) $(CXXFLAGS) -include $(PCH_SRC) -c -o $@ $<
    

    First the PCH gets compiled. Then all cpp commands get compiled with -include lib.hpp this guarantees that lib.hpp.gch will always be searched first before lib.hpp