Design patterns Makefile仅在使用静态模式规则时才重新创建缺少的依赖项文件
考虑清单1中的makefile代码。目标是为每个对象文件%.o生成一个依赖文件$(DEPDIR)/%.d,该文件是在第9行调用C编译器时生成的。具体来说,依赖项文件是在第9行调用C编译器将%.C文件转换为%.o文件时产生的副作用,即第9行发出两个文件:$(DEPDIR)/%.d和%.o 清单1 现在,用清单2所示的隐式规则替换第8行的静态模式规则,否则其他所有内容保持原样: 清单2 静态模式规则版本认为删除/缺少的先决条件$(DEPDIR)/%.d(在第8行)将由第14行的规则更新(我没有预料到),从而使%.o目标过期,因此调用第9行的配方来重建%.o文件 另一方面,隐式模式规则显然认为删除/缺少的先决条件$(DEPDIR)/%.d(在第8行)是未更新的最新的(这是不我所期望的),因此make认为%.o目标是最新的,第9行的配方没有被调用Design patterns Makefile仅在使用静态模式规则时才重新创建缺少的依赖项文件,design-patterns,makefile,static,gnu,rules,Design Patterns,Makefile,Static,Gnu,Rules,考虑清单1中的makefile代码。目标是为每个对象文件%.o生成一个依赖文件$(DEPDIR)/%.d,该文件是在第9行调用C编译器时生成的。具体来说,依赖项文件是在第9行调用C编译器将%.C文件转换为%.o文件时产生的副作用,即第9行发出两个文件:$(DEPDIR)/%.d和%.o 清单1 现在,用清单2所示的隐式规则替换第8行的静态模式规则,否则其他所有内容保持原样: 清单2 静态模式规则版本认为删除/缺少的先决条件$(DEPDIR)/%.d(在第8行)将由第14行的规则更新(我没有预料到
那么,隐式模式规则(清单2)为什么不调用第9行的配方行呢?我没有在GNU制作文档中找到任何解释静态模式规则和隐式规则之间的区别。 < P>如果你想理解这一点,你可以考虑阅读。但要解释一下: 静态模式规则之所以有效,是因为第14行:
13 # Ensure make considers missing $(DEPDIR)/%.d files as "not updated"
14 $(DEPDIR)/%.d : ;
这将创建一个隐式规则,说明如何构建一个提供空配方的.d
文件。配方不起作用,但如果需要运行,它会考虑任何目标取决于它过时。因此,如果文件丢失,make将重建依赖于它的任何目标
删除了原来的错误答案
好吧,现在我自己试过了,并且找到了答案
隐式规则不起作用的原因是考虑了.d
文件。因为它们是中间文件,如果它们不存在,make不会尝试重建它们,除非出于其他原因需要重建它们;这里没有
您可以先删除所有.d
文件,然后触摸.c
文件以强制重建它们,从而证明我的理论是正确的:
$ touch *.c
$ rm deps/*.d
$ make
cc -c -MT a.o -MMD -MF deps/a.d -o a.o a.c
cc -c -MT b.o -MMD -MF deps/b.d -o b.o b.c
cc -c -MT d.o -MMD -MF deps/d.d -o d.o d.c
rm deps/a.d deps/d.d deps/b.d
注意这里的最后一行:删除所有中间文件
如果您查看我上面的博客文章,您会发现我建议将隐式规则更改为显式规则,对您来说,这类似于:
$(SOURCES.c:%.c=$(DEPDIR)/%.d):
现在,所有.d
文件都是显式目标,因此不能是中间文件
请注意上面提到的博客文章给出了一个更好的处理方法。 < P>如果你想理解这一点,你可以考虑阅读。但要解释一下: 静态模式规则之所以有效,是因为第14行:
13 # Ensure make considers missing $(DEPDIR)/%.d files as "not updated"
14 $(DEPDIR)/%.d : ;
这将创建一个隐式规则,说明如何构建一个提供空配方的.d
文件。配方不起作用,但如果需要运行,它会考虑任何目标取决于它过时。因此,如果文件丢失,make将重建依赖于它的任何目标
删除了原来的错误答案
好吧,现在我自己试过了,并且找到了答案
隐式规则不起作用的原因是考虑了.d
文件。因为它们是中间文件,如果它们不存在,make不会尝试重建它们,除非出于其他原因需要重建它们;这里没有
您可以先删除所有.d
文件,然后触摸.c
文件以强制重建它们,从而证明我的理论是正确的:
$ touch *.c
$ rm deps/*.d
$ make
cc -c -MT a.o -MMD -MF deps/a.d -o a.o a.c
cc -c -MT b.o -MMD -MF deps/b.d -o b.o b.c
cc -c -MT d.o -MMD -MF deps/d.d -o d.o d.c
rm deps/a.d deps/d.d deps/b.d
注意这里的最后一行:删除所有中间文件
如果您查看我上面的博客文章,您会发现我建议将隐式规则更改为显式规则,对您来说,这类似于:
$(SOURCES.c:%.c=$(DEPDIR)/%.d):
现在,所有.d
文件都是显式目标,因此不能是中间文件
注意,上面我的博客文章链接提供了一种更好的方法来处理这个问题。经过进一步的实验,我的原始文章中清单1的问题是第14行: 哎呀。我在想什么!?该行应通过替换引用(或通过调用patsubst等)表示: 或者遵循MadScientist的建议,IMHO提供了更好的可读性(并且我稍微改变了一下,使用OBJ而不是源代码) 在哪里 在更改/修复第14行之后,我的makefile始终调用配方行第9行(在清单1中),为静态模式规则案例和隐式规则案例重建已删除/丢失的依赖项文件 [编辑]
根据MadScientist的评论,我已经从makefile中删除了.PRECIOUS行,因为它不再需要了(在进行上述更改之后),而.PRECIOUS行可能会导致不必要的行为。在进一步实验之后,我的原始帖子中清单1的问题是第14行: 哎呀。我在想什么!?该行应通过替换引用(或通过调用patsubst等)表示: 或者遵循MadScientist的建议,IMHO提供了更好的可读性(并且我稍微改变了一下,使用OBJ而不是源代码) 在哪里 在更改/修复第14行之后,我的makefile始终调用配方行第9行(在清单1中),为静态模式规则案例和隐式规则案例重建已删除/丢失的依赖项文件 [编辑] 根据MadScientist的评论,我已经从makefile中删除了.PRECIOUS行,因为它不再需要(在进行上述更改之后),而.PRECIOUS行可能会导致不必要的行为。谢谢。FW
$(SOURCES.c:%.c=$(DEPDIR)/%.d):
$(DEPDIR)/%.d: ;
$(OBJS:%.o=$(DEPDIR)/%.d): ;
DEPFILES := $(OBJS:%.o=$(DEPDIR)/%.d)
$(DEPFILES): ;
OBJS.c := $(SOURCES.c:%.c=%.o)
OBJS.cc := $(SOURCES.cc:%.cc=%.o)
OBJS := $(OBJS.c) $(OBJS.cc)