Rebuilding object files when a header changes - makefile

I have the following rules in my Makefile:
%.o: $(HFILES)
%.o: %.c
$(CC) $(CFLAGS) $*.c
where HFILES contains all headers of my project.
The Problem is that this does not rebuild the object files when a header changes as intended. Why does the first line not add the headers to the prerequisites of the object files?

Because that's not how pattern rules work. The documentation for pattern rules says that when you create a pattern rule with no recipe that cancels the pattern rule (that is, deletes it).
Since your first line is creating a pattern rule with a target %.o and prerequisites $(HFILES) but no recipe, that line simply cancels a pattern rule (which doesn't exist anyway).
You can write:
%.o: %.c $(HFILES)
$(CC) $(CFLAGS) -c -o $# $<
(you shouldn't put the -c flag in your CFLAGS variable).
Be aware that, of course, this means that if ANY header file in HFILES changes, ALL .o files that use this pattern will be rebuilt.

Related

Does the target .SUFFIX have any meaning in a Makefile?

In a Makefile I encountered:
.SUFFIX: .c
Is that a misspelling of .SUFFIXES: .c, because I can't find anything about .SUFFIX only. Does this do anything at all?
If the Makefile only uses pattern rules, do I even need that hanging around in the Makefile at all?
Assuming you are using GNU make, unless there is really a user target named .SUFFIX, this is probably a misspelling of .SUFFIXES: .c. And if there is no recipe you can safely remove it: without a recipe it's useless.
If it was .SUFFIXES: .c and if it had a recipe it would redefine the implicit rules for:
%: %.c
<recipe>
which is:
LINK.c = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
%: %.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#

How to make makefile to use pattern rule?

Having this simple makefile:
VPATH = include
CC := gcc
CFLAGS := -I include -Wall -pedantic
%: %.o include.o
$(CC) -o $# $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
When I trigger it with the name of a program (the same name as is source with .c extension), I would expect to trigger the first rule (since I provided just a name without extension) and the the second one, because for the first rule, there is %.o prerequisite, which is exactly the second rule.
Having these file in pwd:
client.c include makefile server6.c server.c
Now If I make make server:
It does
gcc -I include -Wall -pedantic server.c -o server
In other words, The second rule is not triggered. there is no step with makeing object files, even though the object file is in the first rule as prerequisite. So how is that possible? The make is simply ignoring the prerequisite and trying to make just with the first rule. How to fix that?
That's because make has a built-in rule for %: %.c and make will always choose a pattern rule that can directly create the target over a pattern rule that requires another pattern rule:
Note however, that a rule whose prerequisites actually exist or are mentioned always takes priority over a rule with prerequisites that must be made by chaining other implicit rules.
You can run make -r to remove all the built-in rules, or else remove it yourself by adding:
% : %.c
to your makefile.
You can see all built-in rules by running make -p -f/dev/null

Adding additional dependencies for all files with a given extension

Let's say I am using the implicit rule to build an .o file from a .c file.
If I want to add a specific additional dependency for one particular .o file, it is as easy as adding a rule without a recipe:
file.o : header.h
This makes file.o depend on header.h in addition to file.c.
What if I want to do that for all .o files? The following doesn't work:
%.o : header.h
For this to make sense, header.h must a header that is (and has to be) included by every .c file
and is hence a prerequisite of every .o file. If that is your situation you
need to write your own pattern rule, like:
%.o: %.c header.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
But the usual approach to managing header file dependencies is Auto-Dependency Generation
Later
My goal was to avoid duplicating the existing implicit rule (the recipe part) for $(CC) compilation. Is that possible?
You have to define a new pattern rule that adds header.h to the %.c prerequisite,
and has the appropriate recipe. In fact I ought
to have advised you also to cancel the builtin pattern rule:
%.o: %.c
%.o: %.c header.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#

make 'vpath' directive, why isn't it sufficient for this prerequisite?

The following example makefile works as expected, using vpath to find object files and source files. But in the last line, where i tell make about the dependency of one object file on the other, I need to specify the directory $(objd)/ of the prerequisite file, otherwise i get an error (see error message below the code). How come the vpath directive isn't sufficient in the last line?
# Program Name
prog = avpar
#dirs
objd=obj
modd=mod
# extra places to search for prerequisites
vpath %.f90 ../modules
vpath %.o obj/
# etc
FC = gfortran
flags = -I$(modd) -J$(modd) #-fopenmp
obj_files = $(prog).o rw_mod.o
# compile
p$(prog): $(obj_files)
$(FC) $(flags) $^ -o $#
$(objd)/%.o: %.f90
$(FC) $(flags) -c $< -o $#
$(objd)/$(prog).o: $(objd)/rw_mod.o
That is, changing the last line to:
$(objd)/$(prog).o: rw_mod.o
gives the error:
make: *** No rule to make target 'rw_mod.o', needed by 'obj/avpar.o'. Stop.
EDIT
with this form of the last lines it does also work, without the directory specification:
#compile
p$(prog): $(obj_files)
$(FC) $(flags) $^ -o $#
$(objd)/rw_mod.o: rw_mod.f90
$(FC) $(flags) -c $< -o $#
$(objd)/$(prog).o: $(prog).f90 rw_mod.o
$(FC) $(flags) -c $< -o $#
vpath can only be used to find prerequisites that exist.
Makefiles rule 3
Use VPATH to locate the sources from the objects directory, not to locate the objects from the sources directory.
There's no rule that matches rw_mod.o so the rule for obj/avpar.o fails, vpath won't prepend stuff during prerequisite rule lookup, the only way it would work here would be if obj/rw_mod.o already existed.
It's unlikely that rule is correct anyway, why would one object file depend on another?

Makefile decoupled dependencies

With the following makefile snippet:
main: main.o f1.o f2.o
$(CC) $(CFLAGS) -o program main.o f1.o f2.o
main.o: main.cc
$(CC) $(CFLAGS) -c main.cc
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
f2.o: f2.cc
$(CC) $(CFLAGS) -c f2.cc
If I just change one file, only that file get recompiled when I rerun make, as desired. However, I'm having a hard time generalizing this without having to list each file individually. When I try something like:
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -o $# -c $(patsubst %.o,%.cc,$#)
It builds each object file individually, but each object file depends on ALL my sources, so a change in any one file causing a full recompile. What's a good way to accomplish this?
Basically,
you do have to list each .o file's dependencies individually.
For example, each .o is likely to depend on a different bunch of headers.
Taking your f1.o, you need something like:
f1.o: include/i.h
f1.o: another.h dir/and-another.h
f1.o: f1.cc
$(CC) $(CFLAGS) -c f1.cc
(you can have as many dependency lines for a target as you like).
Maintaining that list is a nightmare.
Broken dependency lists render your Makefile worse than useless—you might as well use a batch file.
All is not lost!
If you are tidy,
you can get the compiler to do it automatically,
and pretty much for free.
Makes your Makefile tidier to boot.
Win Win.
As Ismail Badawi commented, pattern rules provide a nice solution. They are a type of implicit rule for make. Basically, implicit rules are automatic recipes based off the file extension. For example, make knows how to convert .c files into .o files implicitly. By default make will run the following recipe for .c files (see the rule catalogue):
$(CC) $(CPPFLAGS) $(CFLAGS) -c
You can modify the process either by setting the variables CC, CPPFLAGS, and CFLAGS, or by defining a pattern rule:
%.o: %.c
$(CC) $(CFLAGS) -c $<
The "$<" above matches the name of the first prerequisite, which will be the .c file in this example. See Beta's comment and automatic variables.

Resources