vendredi 1 novembre 2019

Makefile recreates missing dependency files only when a static pattern rule is used

Consider the makefile code in Listing 1. The goal is to generate a dependency file $(DEPDIR)/%.d for each object file %.o generated when the C compiler is invoked on line 9. Specifically, the dependency files are generated as a side-effect of invoking the C compiler on line 9 to translate a %.c file into a %.o file--i.e., line 9 emits two files: $(DEPDIR)/%.d and %.o.

Listing 1.

1   DEPDIR := deps
2
3   SOURCES.c  := $(wildcard *.c)
4   OBJS.c  := $(SOURCES.c:.c=.o)
5
6   CPP_DEPFLAGS = -MT $@ -MMD -MF $(DEPDIR)/$*.d
#
#   Other rules, variable definitions, etc. are here...
#
7   %.o : %.c
8   $(OBJS.c) : %.o : %.c $(DEPDIR)/%.d | $(DEPDIR)
9       $(COMPILE.c) $(CPP_DEPFLAGS) $(OUTPUT_OPTION) $<
10
11  $(DEPDIR) : ; mkdir -p $@
12
13  # Ensure make considers missing $(DEPDIR)/%.d files as "not updated"
14  $(DEPDIR)/%.d : ;

This makefile code works as desired, but I don't understand why (see below). Specifically, invoking make creates the DEPDIR folder if it does not exist, and the recipe on line 9 emits the $(DEPDIR)/%.d files as well as the %.o files.

Now assume the user deletes one or more of the %.d files, or the entire DEPDIR folder. Reinvoking make rebuilds the missing dependency files as desired, but again, I don't understand why.

$ rm -fr depdir *.o
$ make # Generates DEPDIR and the $(DEPDIR)/%.d files
$ rm -fr depdir
# NB: The %.o files still exist
$ make # Regenerates DEPDIR and the $(DEPDIR)/%.d files

Now replace the static pattern rule on line 8 with the implicit rule shown in Listing 2, and otherwise leave everything else as it was:

Listing 2.

8   %.o : %.c $(DEPDIR)/%.d | $(DEPDIR)
9       $(COMPILE.c) $(CPP_DEPFLAGS) $(OUTPUT_OPTION) $<

When an implicit rule is used, make does not regenerate deleted/missing dependency files--which is the outcome I expected:

$ rm -fr depdir *.o
$ make # Generates DEPDIR and the $(DEPDIR)/%.d files
$ rm -fr depdir
# NB: The %.o files still exist
$ make # Generates DEPDIR only; DOES NOT regenerate the $(DEPDIR)/%.d files

It's as though the static pattern rule version considers the prerequisite $(DEPDIR)/%.d (on line 8) to be updated (which I did NOT expect), thus making the %.o target out-of-date, and therefore the recipe on line 9 is invoked to rebuild the %.o file.

The implicit pattern rule, on the other hand, apparently considers the prerequisite $(DEPDIR)/%.d (on line 8) to be not updated (which is what I expected), and therefore make considers the %.o target up-to-date and the recipe on line 9 is not invoked.

So why does the static pattern rule version (Listing 1) regenerate the missing $(DEPDIR)/%.d files, while the implicit pattern rule version (Listing 2) does not? I don't find anything in the GNU Make documentation to explain this difference.

Aucun commentaire:

Enregistrer un commentaire