【问题标题】:Gnu Make auto-dependency generationGnu Make 自动依赖生成
【发布时间】:2018-07-04 18:13:01
【问题描述】:

基于this famous link并改编自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)

为了不要让这个问题太长,深入讨论为什么我认为上面sn-p中注释的所有行都是不必要的,我会用简短的​​形式问它;如果我只是将这个 sn-p 更改为:

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)

我还有两个额外的疑问;在上面的第一个链接中,它说

据报道,某些版本的 GCC 可能会留下目标文件 比依赖文件旧,这会导致不必要的重建。

但是,在gist(上面的第二个链接)中,touch 命令被删除,并且由于依赖文件不再是任何规则的先决条件,是否有任何理由继续包含它?这个“gcc bug”是否仍然适用于任何形式?

第二个疑问与目录创建有关,移至仅订单规则;我是否需要制定“仅限订单”$(DEPDIR)/% 规则.PRECIOUS?如果%.o 配方失败,我不知道make 是否会尝试删除目录,因为我不知道仅订购规则的具体功能。

【问题讨论】:

    标签: makefile dependencies auto-generate


    【解决方案1】:

    您不能删除%.d 先决条件。在您链接的页面中需要is explained 的原因。

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

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

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

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

    【讨论】:

    • 关于“删除两次”的评论,你又在同一个目标之下,(好的,有额外的 .d 依赖)。为什么这不是多余的?
    • 第一个删除了内置模式,因为它没有配方。请参阅gnu.org/software/make/manual/html_node/Canceling-Rules.html 第二行是使用新配方创建新模式规则的开始。它们根本不是一回事。
    • 好的,我理解删除依赖文件的问题,但它也会重新创建 .o,它已经更新,并且会导致不必要的工作量,因为重新创建依赖文件是比编译快得多的操作。想想删除main.d 的例子。对于这种情况,什么是更好的解决方案?我正在考虑三个选项:仅订购 %.d 依赖,%.d 取决于 %.cpp 将我们带到第 1 方,或者两个不同的食谱,使用 ifeq according to whether %.cpp` 在 $? 或不是。
    • 我看不出纯订单%.d 先决条件会有什么不同。同样很明显,您不能使用ifeq,因为这是一个 make 构造,不能在配方中使用。您必须使用 shell 条件或 $(if ...) make 函数。 IMO 这是针对罕见极端情况的微优化(人们不应该手动删除.d 文件),不值得为避免编译步骤而增加复杂性。
    • 您可以在配方中放置一个 make 条件,但是它将在解析 makefile 时进行评估,而不是在扩展配方时进行评估。这意味着您无法检查任何自动变量等的内容,因为它们在解析 makefile 时不可用,只有在稍后运行配方时才可用。所以你不能用这些语句来检查$?是否包含一个特定的值:它总是空字符串。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    • 2015-05-09
    • 2010-10-09
    • 2012-02-21
    相关资源
    最近更新 更多