3

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?

disquisitiones
  • 167
  • 2
  • 11
  • 1
    where in make file you are precompiling header? Where it does: `g++ -O2 -H -Wall -std=c++17 -c lib.hpp`? – Marek R Dec 29 '18 at 12:45
  • actually I dont't build the lib.hpp.gch via the makefile, I've built it manually with the command shown at the beginning – disquisitiones Dec 29 '18 at 14:32

1 Answers1

7

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

Cinder Biscuits
  • 4,880
  • 31
  • 51
  • I've added the compilation of the pch in the makefile and now it works. Still not clear why though. Shouldn't a command issued by make be the same as the command issued directly from the command line? How the compilation of the pch in the makefile could make a difference? – disquisitiones Dec 29 '18 at 14:43
  • I include the lib.hpp always as the first token in the .cpp files, so this is equivalent to the use of the -include flag – disquisitiones Dec 29 '18 at 14:45
  • 2
    The `-include` flag causes the compiler to search *`precompile.h.gch`* before `precompile.h` As you have seen, compiling with `gcc` directly yields the same result because it will always search for PCHs first when used like that, the same is not true when `gcc` is called from `make` nor is it true in other compilers like `clang` where PCHs aren't searched for unless `-include` is specified. – Cinder Biscuits Dec 29 '18 at 15:11
  • According to the GCC documentation, "... As it searches for the included file (see Search Path in The C Preprocessor) the compiler looks for a precompiled header in each directory *just before it looks for the include file in that directory*. The name searched for is the name specified in the #include with ‘.gch’ appended. If the precompiled header file cannot be used, it is ignored." So the precompiled header, if existing in the search path, should always take precedence by default over the corresponding header file. – disquisitiones Dec 29 '18 at 15:48
  • The proof is that in my modified makefile I've just added the compilation of the precompiled header. I'm **not** using the -include flag and it works perfectly. So the mistery still remains. – disquisitiones Dec 29 '18 at 15:50