Consider the following simple makefile:
#------------------------------#
# List all object files #
#------------------------------#
objects := main.o foo.o bar.o baz.o
#------------------------------#
# Define pattern rule #
# for *.c -> *.o #
#------------------------------#
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
#------------------------------#
# Define the rule to make #
# the end result #
#------------------------------#
.PHONY all
all: myApp.elf
myApp.elf: $(objects)
$(CC) $(objects) -o myApp.elf $(LFLAGS) $(LIBS)
If you give the command make all
, GNU make will start at the target myApp.elf
. It looks at all the prerequisites main.o
, foo.o
, bar.o
and baz.o
and attempts to update them.
To do that, make uses the pattern rule defined in the middle of the makefile. This pattern rule expands like this:
main.o: main.c
$(CC) -c $(CFLAGS) main.c -o main.o
foo.o: foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o: bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o
baz.o: baz.c
$(CC) -c $(CFLAGS) baz.c -o baz.o
So far, so good. But you can clearly see that dependencies (included h-files) are missing.
I found some sources that recommend the following approach:
#------------------------------#
# List all object files #
# and all dependency files #
#------------------------------#
objects := main.o foo.o bar.o baz.o
deps := $(objects:.o=.d)
#------------------------------#
# Define pattern rule #
# for *.c -> *.o #
#------------------------------#
%.o: %.c
$(CC) -c $(CFLAGS) -MMD -MP $< -o $@
#------------------------------#
# Define the rule to make #
# the end result #
#------------------------------#
.PHONY all
all: myApp.elf
myApp.elf: $(objects)
$(CC) $(objects) -o myApp.elf $(LFLAGS) $(LIBS)
-include $(deps)
I'm trying to wrap my head around this approach. First GNU make reads the makefile and looks for other included makefiles (see GNU make manual paragraph 3.5 "How Makefiles Are Remade"). Make attempts to update each included makefile it can find (in this case the dependency files main.d
, foo.d
, bar.d
and baz.d
) before starting execution of the makefiles. I've summarized this in the following figure:
Exactly. I don't see any rule where the dependency files are specified as targets.
Please help me to understand what actually happens next. Please, write your answer as a step-by-step chain of events. That would be great to gain insight in the matter.
Note:
Of course, the -MMD
and -MP
arguments in the compilation command (see pattern rule in the middle) lead to dependency files getting created. But the targets of this pattern rule are the object-files, not the dependency-files.
Note:
I had wrongly assumed that GNU make has an implicit rule getting activated here. But thanks to your comments and answers, I now know this was wrong :-)