Search code examples
makefiledependenciesauto-generate

Gnu Make auto-dependency generation


Based on this famous link and adapted from this gist, and supposing that all of your source files are .cpp, you get easily a solution like this to have auto-dependence generation:

SRCS := $(wildcard *.cpp */*.cpp)

DEPDIR := .d
DEPS := $(SRCS:%.cpp=$(DEPDIR)/%.d)

# Temporary .Td dependence file... ?
DEPFLAGS = -MT $@ -MD -MP -MF $(DEPDIR)/$*.Td

# Isn't it better a order-only prerequisite?
$(shell mkdir -p $(dir $(DEPS)) >/dev/null)

%.o: %.cpp # Removal of implicit rules... ? Twice?
%.o: %.cpp $(DEPDIR)/%.d  # Dependency on .d... ?
        g++ -o $@ $(DEPFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c $<
        # Avoid some bugs?
        mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@

# If the `%.d` dependency is removed, is this still necessary?
.PRECIOUS = $(DEPDIR)/%.d
$(DEPDIR)/%.d: ;

-include $(DEPS)

To don't make this question too long discussing deeply why I think that all of the lines commented in the snippet above are innecesary, I will ask it in a short form; is there any difference in behaviour if I just change this snippet to:

SRCS := $(wildcard *.cpp */*.cpp)
DEPDIR := .d
DEPS := $(SRCS:%.cpp=$(DEPDIR)/%.d)

DEPFLAGS := -MT $@ -MD -MP -MF $(DEPDIR)/$*.d

$(DEPDIR)/%:
        mkdir -p $@

%.o: %.cpp | $(DEPDIR)/$(dir %)
        g++ -o $(DEPFLAGS) $(CXXFLAGS) $(CPPFLAGS) -c $<
        # touch $(DEPDIR)/$.d # ??

-include $(DEPS)

I have still two extra doubts; in the first link above, it says that

it’s been reported that some versions of GCC may leave the object file older than the dependency file, which causes unnecessary rebuilds.

However, in the gist (second link above), the touch command is removed, and since the dependence file is no longer prerequisite of any rule, is there any reason to keep including it? Does this "gcc bug" still apply in any form?

The second doubt is related to the directory creation, moved to an order-only rule; do I need to make the "order-only" $(DEPDIR)/% rule .PRECIOUS? I don't know if make will attempt to remove the directory if the %.o recipe fails, because I don't know the concrete features of order-only rules.


Solution

  • You cannot remove the %.d prerequisite. The reason this is needed is explained in the page you linked.

    I don't know what you mean by your comment Removal of implicit rules... ? Twice?. The removal of the implicit rule is needed, to ensure that our new implicit rule is used, and we only remove it once.

    The temporary file .Td is used in case someone uses ^C or similar to kill their make job right in the middle of creating this file. By writing to a temporary file then only atomically replacing the real file once we know it's complete, we never have to worry about partial files which could cause the next invocation of make to generate an error or, worse, not recompile source files that should be recompiled.

    Regarding the comment about object files older than the dependency file, first the gist you link to uses clang not GCC and perhaps Clang doesn't have this issue (or perhaps it does but people don't realize it). Second that update to the blog post is relatively recent as people have reported this issue to me with GCC. I've not seen it myself (I only use GCC) so maybe it's only an issue with some versions of GCC.

    Regarding .PRECIOUS, make never (currently) recursively deletes directories so it won't delete any non-empty directory regardless of that setting.