Precompiled headers not used by GCC when building with a makefile - c++

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?

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

Related

Makefile, using mpiCC compiler for main.cpp and g++ for other functions of the src code

I have created a source code in C++ and I want to compile it by using makefiles. The problem is that I want my main functions to compile with mpiCC and the other functions to compile with g++. Is this possible?
What should I change in the following makefile?
Thanks in advance,
Ilias
.PHONY: all clean
CC=mpiCC #g++
CFLAGS=-c -O3
LOCAL_INC_PATH = ../include
SOURCES= main.cpp \
f1.cpp \
f2.cpp
OBJECTS=$(patsubst %.cpp,%.o,$(SOURCES))
LIP = $(LOCAL_INC_PATH)
HEADERS = $(LIP)/func_all.h
all: $(OBJECTS)
$(CC) $^ -o MIE -I$(LOCAL_INC_PATH)
%.o: %.cpp
$(CC) $(CFLAGS) $^ -I$(LOCAL_INC_PATH)
clean:
rm *.$(OBJECTS)
You can put an additional explicit rule for main.cpp:
# ...
CC=g++
# ...
SOURCES= f1.cpp \
f2.cpp
OBJECTS=$(patsubst %.cpp,%.o,$(SOURCES)) main.o
# ...
main.o : main.cpp
mpiCC $(CFLAGS) $^ -I$(LOCAL_INC_PATH)
# ...
It is possible, of course.
CC=g++ # compile everything with g++
main.o : CC=mpiCC # compile main.o with mpiCC
The above uses target-specific variables. When compiling main.o it replaces the value of CC with mpiCC.
Please note, the convention is that CC variable is the C compiler, whereas CXX is the C++ one. Same applies to flags, CFLAGS vs CXXFLAGS.

Creating a robust Makefile for C++ program

Consider the following trivial Makefile. Notice that there are two classes with corresponding .h and .cpp files for each.
output: main.o class1.o class2.o
g++ main.o class1.o class2.o -o output
main.o: main.cpp
g++ -c main.cpp
class1.o: class1.cpp class1.h
g++ -c class1.cpp
class2.o: class2.cpp class2.h
g++ -c class2.cpp
clean:
rm *.o output
Is this Makefile robust? How can I make it more robust? Can someone provide a more robust version of this Makefile? It will be running on a 64 bit Red Hat Linux or CentOS machine.
If it matters, I am using:
-gcc --version 4.8.4 (From the GNU Compiler Collection)
-GDB version: GNU gdb (Ubuntu 7.7.1 -0ubuntu5~14.04.2) 7.7.1
I don't think your original makefile is far off the mark. I've just made a few additions:
Added a default all target - it's good to be explicit
Use the CXXFLAGS environment variable in all the calls to g++
Make main.o depend upon class1.h and class2.h as discussed
Specify that clean is a PHONY target just to be on the safe side if you add build artifact called clean
ALL := output
all : $(ALL)
output: main.o class1.o class2.o
g++ $(CXXFLAGS) main.o class1.o class2.o -o output
main.o: main.cpp class1.h class2.h
g++ $(CXXFLAGS) -c main.cpp
class1.o: class1.cpp class1.h
g++ $(CXXFLAGS) -c class1.cpp
class2.o: class2.cpp class2.h
g++ $(CXXFLAGS) -c class2.cpp
.PHONY : clean
clean:
rm *.o output
I would write something like
CXX = g++
# mandatory build flags
AM_CXXFLAGS = -Wall -W -std=gnu++11
# optional build flags
CXXFLAGS = -O2 -Werror
# mandatory link flags
AM_LDFLAGS = -Wl,-as-neeeded
output: main.o class1.o class2.o
${CXX} ${AM_LDFLAGS} ${LDFLAGS} $(filter %.o,$^) -o $#
%: %.cpp
${CXX} ${AM_CXXFLAGS} ${CXXFLAGS} $< -c -o $#
class1.o: class1.cpp class1.h
class2.o: class2.cpp class2.h
the *FLAGS are following automake notation: AM_* mean mandatory flags, the normal flags contain local settings (e.g. debugging or optimiziation).
Usually, AM_CPPFLAGS and CPPFLAGS with preprocessor flags (-I ...) should be used too but I omitted them here
the output target might need ${LIBS} too which have been omitted here
dependency tracking is more tricky and not implemented; you will have to play with -dM compiler option here...
When your program consists only of the listed 5 files, you can write
output_SOURCES = main.c class1.c class2.c class1.h class2.h
output: ${output_SOURCES}
${CXX} ${AM_CXXFLAGS} ${CXXFLAGS} ${AM_LDFLAGS} ${LDFLAGS} $(filter %.cpp,$^) -o $# ${LIBS}
directly.
EDIT:
For automatic dependency tracking, you can write
DEPGENFLAGS = \
-MD -MF ${#D}/.${#F}.d -MT '$#'
%: %.cpp
${CXX} ${DEPGENFLAGS} ${AM_CXXFLAGS} ${CXXFLAGS} $< -c -o $#
-include .deps.main.o.d
-include .deps.class1.o.d
-include .deps.class2.o.d
How can I make it more robust?
Use implicit rules, keep it simple.
LDLIBS+=-lstdc++
output: main.o class1.o class2.o
clean:
rm *.o output

Makefile generate dependency automatically does not work

I have four cpp files and so many .h files. I expect my make file generates the appropriate .d file for each .cpp file and compiles them to .o and then links them. Could some one tell me what is wrong with this code? it does not work in the way that it should.
Btw, I am beginner in makefile! Please do not link to somewhere with hard explanation for highly experts.
$make
g++ -c -g -Wall -Wconversion -Wfatal-errors -Wextra -std=c++11 -MD -MP -MF ./bin/obj/app/sim_rhs.d -o bin/obj/app/sim_rhs.o app/sim_rhs.cpp
app/sim_rhs.cpp:49:1: fatal error: opening dependency file ./bin/obj/app/sim_rhs.d: No such file or directory
}
^
compilation terminated.
make: *** [bin/obj/app/sim_rhs.o] Error 1
Cpp Files:
main.cpp
app/sim_rhs.cpp
app/sim_mids.cpp
app/sim_outputs.cpp
Makefile
SOURCES := main.cpp app/sim_rhs.cpp app/sim_mids.cpp app/sim_outputs.cpp
OUTDIR:= ./out
BINDIR:= ./bin
OBJDIR:= ./bin/obj
OBJECTS := $(addprefix $(OBJDIR)/,$(SOURCES:.cpp=.o))
DEPFILES:= $(OBJECTS:.o=.d)
CXX := g++
CXXFLAGS := -c -g -Wall -Wconversion -Wfatal-errors -Wextra -std=c++11 -MD -MP
LIBS:= -lboost_filesystem -lboost_system
# default
%:: $(BINDIR)/sim
# Link the executable
$(BINDIR)/sim: $(OBJECTS)
$(CXX) $(LDFLAGS) $^ -o $# $(LIBS)
run:
$(BINDIR)/sim
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -MF $(OBJDIR)/$*.d -o $# $<
-include $(DEPFILES)
Please avoid duplicate suggestion as I have an existing code. I do not want any other person's makefile template.

Why does this makefile execute a target on 'make clean'

This is my current makefile.
CXX = g++
CXXFLAGS = -Wall -O3
LDFLAGS =
TARGET = testcpp
SRCS = main.cpp object.cpp foo.cpp
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
.PHONY: clean all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
.cpp.o:
$(CXX) $(CXXFLAGS) -c $< -o $#
%.d: %.cpp
$(CXX) -M $(CXXFLAGS) $< > $#
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
It works perfectly with one exception. If the directory is already clean (no *.d, *.o) and I run 'make clean', it re-creates the dependencies, then immediately deletes them:
[user#server proj]$ make
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
g++ -Wall -O3 -c main.cpp -o main.o
g++ -Wall -O3 -c object.cpp -o object.o
g++ -Wall -O3 -c foo.cpp -o foo.o
g++ -Wall -O3 main.o object.o foo.o -o testcpp
[user#server proj]$ make clean
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user#server proj]$ make clean
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user#server proj]$
I don't understand why the second 'make clean' would re-generate the dependency files. How can I avoid this? This isn't a big deal for this contrived example, but for a large project, it can be quite time-consuming.
Thanks.
It's because the .d files are being -included unconditionally. As far as make knows, they could add dependencies or commands to the clean target. All included files are built first for this reason, otherwise you might get an incorrect or failed build. To disable this, you want to conditionally include the dependency files:
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
An alternative solution is to generate the dependency files using touch and have them replaced by actual data as a side-effect of compilation. This is how automake does its dependency tracking, as it makes one-time builds faster. Look into the -MD and -MMD options to gcc if you want to go this route. Use a pattern rule like:
%.d:
#touch $#
To initially create the dependency files.
If you want to skip the include for multiple targets, you can use the filter function.
MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc
# Include only if the goal needs it
ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),)
-include $(DEPS)
endif
It wants to regenerate the dependency files because it always tries to regenerate all of the makefiles, including -include'd makefiles, before doing anything else. (Well, actually, for me it doesn't do that - I have GNU Make 3.81 - so maybe it's a bug in your version that was fixed, or an optimization that mine has and yours doesn't. But anyway.)
The easiest way around this is to write your rules so they generate the .d files as a side effect of regular compilation, rather than giving explicit rules to generate them. That way, when they're not there, Make doesn't know how to generate them so it doesn't try (in a clean tree, the .cpp.o rules are enough, you don't need the header file dependencies). Look at an Automake-generated makefile -- a simple one -- to see how it's done.
The leading - in -include means that make won't complain if the dependencies are missing and can't be remade, but it doesn't mean it won't try to make them first (and, in this case, succeed) -- after all, anything interesting or important could be in the included files, whence the let's-try-making them attempt. I don't think there's a way to stop that.
For docs on include and -include, see here.

Problem with makefile making .gch files instead of.o files

So, I'm making a program to test the efficiency of certain data structures. I have all the .h files and I made a very terrible makefile that probably is wrong, although it seems to work up to a point. Instead of making .o files it makes .gch files, so when it tries to acces all the .o files they are not found. This is my makefile
prog1: main.o dsexceptions.o BinarySearchTree.o SplayTree.o RedBlackTree.o AvlTree.o
g++ -Wall -g -o prog1 main.o dsexceptions.h.gch BinarySearchTree.h.gch SplayTree.h.gch RedBlackTree.h.gch AvlTree.h.gch
main.o: main.cpp AvlTree.h RedBlackTree.h SplayTree.h BinarySearchTree.h dsexceptions.h
g++ -Wall -g -c main.cpp
#shape.o: shape.cpp shape.h grid.h
# g++ -Wall -g -c shape.cpp
dsexceptions.o: dsexceptions.h
g++ -Wall -g -c dsexceptions.h
BinarySearchTree.o: BinarySearchTree.h dsexceptions.h
g++ -Wall -g -c BinarySearchTree.h
SplayTree.o: SplayTree.h dsexceptions.h
g++ -Wall -g -c SplayTree.h
RedBlackTree.o: RedBlackTree.h dsexceptions.h
g++ -Wall -g -c RedBlackTree.h
AvlTree.o: AvlTree.h dsexceptions.h
g++ -Wall -g -c AvlTree.h
clean:
rm -f main main.exe main.o dsexceptions.o BinarySearchTree.o SplayTree.o RedBlackTree.o AvlTree.o *.gch
You don't want to feed your .h files to the compiler. Only compile the .cpp file, which should include your .h files. (The .gch files are precompiled headers.) You don't need .o files for your headers, just #include them in your .cpp file.
prog1: main.o
g++ -Wall -g -o prog1 main.o
main.o: main.cpp AvlTree.h RedBlackTree.h SplayTree.h BinarySearchTree.h dsexceptions.h
g++ -Wall -g -c main.cpp
clean:
rm -f prog1 main.o
You already have the solution from bstpierre, but just for fun here's my version of your makefile:
CC = g++ -Wall -g -o $#
MODULE = AvlTree BinarySearchTree RedBlackTree SplayTree
OBJECTS = $(addsuffix .o,$(MODULES))
prog1: main.o dsexceptions.o $(OBJECTS)
$(CC) $^
main.o: $(addsuffix .h,$(MODULES))
$(OBJECTS) main.o : %.cpp %.h dsexceptions.h
$(CC) -c $&lt
clean:
rm -f main main.exe *.o *.gch
And just for good measure, here is my SConstruct, because SCons's so much better :)
Program('main.cpp') # Yeah, it's that simple :)
You can look at SCons here.