删除Makefile生成的.d文件后未触发重建的原因排查
问题分析与解决
你的问题出在.d文件的规则设计和all目标的依赖逻辑上,我来一步步拆解原因并给出修复方案:
为什么删除.d后make没反应?
当你删除file.d后,make检查all目标的依赖时,确实发现file.d缺失,但看你定义的规则:
$(OUTDIR)/%.d : ;
这个规则的命令是空的(分号代表空命令),make会判定这个目标不需要任何操作就能“完成”——它不会触发.o文件的重建,因为.o已经存在,而.d的规则既没有依赖.o,也没有指定生成.d的实际命令。
另外,你把$(OBJECTS:%.o=%.d)作为all的直接依赖,但这些.d文件并没有和编译过程建立正确的关联,所以make不会主动触发重新编译来生成缺失的.d。
正确的依赖文件生成方式
在Makefile的最佳实践中,我们不会把.d文件作为all的直接依赖,而是通过-include指令自动引入这些依赖文件,让make自动处理头文件依赖,同时保证.d和.o文件同步生成。
修改你的Makefile如下:
DEPFLAGS=-MD -Mo $(OUTDIR)/$*.Td POSTCOMPILE=@mv -f $(OUTDIR)/$*.Td $(OUTDIR)/$*.d && touch $@ VPATH=../src OUTDIR=../out SOURCES:=$(notdir $(wildcard ../src/*.c)) OBJECTS:=$(SOURCES:%.c=$(OUTDIR)/%.o) # 引入.d文件,-前缀表示文件不存在时不报错 -include $(OBJECTS:.o=.d) all: $(OBJECTS) $(OUTDIR)/%.o : %.c @$(CC) $(DEPFLAGS) -c $< -o $@ @$(POSTCOMPILE) # 确保输出目录存在,避免Windows下创建文件失败 $(OBJECTS): | $(OUTDIR) $(OUTDIR): @mkdir -p $@ .PRECIOUS: $(OUTDIR)/%.d
修改要点说明:
- 移除
all对.d文件的直接依赖,改用-include $(OBJECTS:.o=.d)引入依赖文件。-前缀的作用是:如果.d文件不存在,make不会报错,后续编译时会自动生成这些文件。 - 简化
.o文件的规则,无需将.d作为.o的依赖(-include已经会处理头文件依赖,而.d是编译.o时的副产品)。 - 添加输出目录的生成规则,确保编译前目录已存在,避免Windows环境下的文件创建失败。
验证修改后的行为
- 首次执行
make:正常生成file.o和file.d。 - 删除
file.d后执行make:如果.o文件仍是最新状态,make不会重新编译,但如果后续修改了file.c或它依赖的头文件,make会自动重新编译.o并同步生成新的.d。
如果你的需求是只要.d缺失就强制重新编译,可以调整规则让.o依赖.d,但会引入额外的预编译步骤:
$(OUTDIR)/%.o : %.c $(OUTDIR)/%.d @$(CC) $(DEPFLAGS) -c $< -o $@ @$(POSTCOMPILE) $(OUTDIR)/%.d : %.c @$(CC) $(DEPFLAGS) -E $< -o $(OUTDIR)/$*.Td @mv -f $(OUTDIR)/$*.Td $(OUTDIR)/$*.d
不过这种方式效率略低,一般更推荐前面的-include标准方案。
内容的提问来源于stack exchange,提问作者tanascius
相关产品推荐
相关产品推荐

