Gnu Make 自动依赖生成

Gnu Make auto-dependency generation

基于this famous link and adapted from this gist,假设你所有的源文件都是.cpp,你很容易得到像这样的自动依赖生成的解决方案:

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)

为了不要让这个问题太长,深入讨论为什么我认为上面代码段中评论的所有行都是不必要的,我会以简短的形式提问;如果我只是将此代码段更改为:

,行为会有什么不同吗?
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)

我还有两个疑惑;在上面的第一个 link 中,它说

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

但是,在gist(上面的第二个link)中,touch命令被删除了,并且由于依赖文件不再是任何规则的前提条件,是否有任何有理由保留它吗?这 "gcc bug" 仍然适用于任何形式吗?

第二个疑点与目录创建有关,移至order-only规则;我需要制定 "order-only" $(DEPDIR)/% 规则 .PRECIOUS 吗?我不知道如果 %.o 配方失败,make 是否会尝试删除目录,因为我不知道 order-only 规则的具体特征。

您无法删除 %.d 先决条件。在您 link 编辑的页面中 is explained 需要这样做的原因。

我不知道你的评论是什么意思删除隐式规则...?两次?。需要删除隐式规则,以确保使用我们新的隐式规则,我们只删除一次。

临时文件 .Td 用于防止有人在创建此文件的过程中使用 ^C 或类似命令终止他们的 make 作业。通过写入一个临时文件然后只在我们知道它完成后才自动替换真实文件,我们永远不必担心部分文件可能导致下一次调用 make 产生错误,或者更糟的是,不重新编译应该是的源文件重新编译。

关于关于对象文件早于依赖文件的评论,首先要点你 link 使用 clang 而不是 GCC,也许 Clang 没有这个问题(或者可能有但是人们没有意识到这一点)。其次,博客 post 的更新相对较新,因为人们已经通过 GCC 向我报告了这个问题。我自己没有看到它(我只使用 GCC)所以可能这只是某些版本的 GCC 的问题。

关于 .PRECIOUSmake 从不(当前)递归删除目录,因此无论该设置如何,它都不会删除任何非空目录。