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: main.cpp, a.h, and b.h. main.cpp include sa.h and a.h includes b.h.
My makefile looks like this:
prog: main.cpp a.h
g++ main.cpp -o prog
a.h: b.h
When any combination of a.h, b.h, and main.cpp is changed, I expect prog to be recompiled. Despite this, prog is only recompiled when a.h or main.cpp is changed, with the last line seeming to be ignored.
What am I doing incorrectly and 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):
prog: main.cpp a.h b.h
g++ ...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With