I am attempting to write a makefile that is able to determine when headers were changed and then recompile the corresponding .cpp files. To test this, I created three files:
What am I doing incorrectly
Your rule:
a.h: b.h
merely tells make
that a.h
depends on b.h
, i.e. that a.h
will need to
be (re)made, in whatever manner make
can determine from the makefile, if
a.h
is older than b.h
or doesn't exist.
It doesn't tell make
what to do to remake a.h
from b.h
. Your makefile
contains no recipe for remaking a.h
from b.h
. It only contains a recipe
for remaking prog
from main.cpp
and a.h
, namely:
prog: main.cpp a.h
g++ main.cpp -o prog
Furthermore make
, of course, has no builtin rule with a recipe for making
a.h
from b.h
. So in the absence of any recipe for making a.h
from b.h
it assumes that this dependency requires nothing to be done. There is no
other reasonable default. So even if a.h
is older than b.h
, nothing
is done to a.h
; and although prog
depends on a.h
, nothing need be done
to prog
on that account.
This is fortunate, because in fact you don't want a.h
to be remade in
any manner whatever when b.h
changes, and you don't want main.cpp
to be
remade in any manner whatever when a.h
or b.h
changes. You want prog to be
remade when any of them changes. What you want is expressed by any of the
following makefiles:
1
prog: main.cpp a.h b.h
g++ main.cpp -o prog
2
prog: main.cpp a.h
g++ main.cpp -o prog
prog: b.h
3
prog: main.cpp b.h
g++ main.cpp -o prog
prog: a.h
4
prog: main.cpp
g++ main.cpp -o prog
prog: a.h b.h
5
prog: main.cpp
g++ main.cpp -o prog
prog: a.h
prog: b.h
(and some more). They're all equivalent. They all say that prog
depends
on main.cpp
, a.h
and b.h
and they all say what is to be done whenever
prog
needs to remade, namely:
g++ main.cpp -o prog
how can I accomplish what I want without adding the full and complete set of headers to each individual .cpp file like this (since for larger projects this could become extremely cumbersome)
Indeed it would, and for that reason GCC compilers have for a very long time had
a feature for generating mini-makefiles that express the dependency of
the object file that is going to be generated upon each of the header files that
are read in order to make the object file. GNU make can exploit this feature
to generate those dependency files and include them in a makefile for building GCC target(s). This co-operation between
GCC and make
is called auto-dependency generation (or similar). The
question of how to do it in a makefile is a duplicate of this one
and if you google, e.g. "gcc auto generate dependencies" you can also find guru treatments.
In a comment you suggest that you aren't yet sufficiently expert with GNU make to be confident with the auto-dependency generation techniques illustrated in those answers. Well, you can begin to get the hang of it with a rudimentary implementation as simple as this (which also makes the makefile more normal in other respects):
Makefile
.PHONY: all clean
all: prog
prog: prog.o
prog.o: main.cpp
g++ -MMD -c -o prog.o main.cpp
prog: prog.o
g++ -o prog prog.o
clean:
rm -f prog *.o *.d
-include prog.d
-MMD
is the GCC preprocessor option that generates the dependency file
prog.d
. Here is the documentation of -MMD
prog.d
is a mini-makefile:
$ cat prog.d
prog.o: main.cpp a.h b.h
expressing all of the dependencies of prog.o
. The first time this runs,
the include
-ed makefile prog.d
will not exist, which would be a fatal make
error but for the fact that the -
prefix tells make
to ignore that error.
So make
proceeds and everything, including prog.d
gets made, and thereafter
prog.d
will be regenerated whenever any rule - including the rule in prog.d
itself - requires prog.o
to be recompiled.