You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Makefile中make re未执行所有模式规则的问题排查

Make re执行时依赖文件未重新生成的问题与解决

问题描述

执行make re时出现异常:%.d模式规则会在fclean执行前触发,而fclean删除依赖文件后,后续all阶段仅调用%.o模式规则,未重新生成.d依赖文件。

make执行输出

mkdir -p srcs/depends
c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -MM srcs/tests.cpp -o srcs/depends/tests.d
c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -MM srcs/main.cpp -o srcs/depends/main.d
mkdir -p srcs/obj
c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/main.cpp -o srcs/obj/main.o
c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/tests.cpp -o srcs/obj/tests.o
c++ -lstdc++ srcs/obj/main.o srcs/obj/tests.o -o main

make re执行输出

rm -f -rv srcs/obj srcs/depends 
srcs/obj/main.o
srcs/obj/tests.o
srcs/obj
srcs/depends/main.d
srcs/depends/tests.d
srcs/depends
rm -f main
mkdir -p srcs/obj
c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/main.cpp -o srcs/obj/main.o
c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/tests.cpp -o srcs/obj/tests.o
c++ -lstdc++ srcs/obj/main.o srcs/obj/tests.o -o main

原Makefile内容

NAME        = main
SRCSDIR     = srcs
SRCS        = $(wildcard $(SRCSDIR)/*.cpp)
OBJSDIR     = srcs/obj
OBJS        = $(SRCS:$(SRCSDIR)/%.cpp=$(OBJSDIR)/%.o)
DEPENDSDIR  = srcs/depends
DEPENDS     = $(SRCS:$(SRCSDIR)/%.cpp=$(DEPENDSDIR)/%.d)
CPPFLAGS    = -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes
DEPFLAGS    = -MM
LDFLAGS     = -lstdc++


all: $(NAME)

$(NAME): $(OBJS)
    c++ $(LDFLAGS) $^ -o $@

$(OBJSDIR)/%.o: $(SRCSDIR)/%.cpp | $(OBJSDIR)
    c++ $(CPPFLAGS) -c $< -o $@

$(DEPENDSDIR)/%.d: $(SRCSDIR)/%.cpp | $(DEPENDSDIR)
    c++ $(CPPFLAGS) $(DEPFLAGS) $< -o $@

$(OBJSDIR) $(DEPENDSDIR):
    mkdir -p $@

-include $(DEPENDS)

clean:
    $(RM) -rv $(OBJSDIR) $(DEPENDSDIR) 

fclean: clean
    $(RM) $(NAME)

re: fclean all

.PHONY: all clean fclean re

原因分析

  • Make在执行任何目标前,会先完成整个Makefile的解析过程,此时-include $(DEPENDS)会触发%.d规则生成依赖文件(如果文件不存在或过时),这一步发生在fclean执行之前。
  • fclean删除.d文件后,Make已经完成了依赖解析,后续执行all时不会再重新触发%.d规则——因为Make认为这些依赖目标已经处理过,不会再检查文件是否存在。

解决方案

将依赖文件的生成逻辑整合到.o文件的编译规则中,利用编译器的自动依赖生成选项,避免单独的%.d规则,确保make re时能同步生成依赖文件。

修改后的Makefile

NAME        = main
SRCSDIR     = srcs
SRCS        = $(wildcard $(SRCSDIR)/*.cpp)
OBJSDIR     = srcs/obj
OBJS        = $(SRCS:$(SRCSDIR)/%.cpp=$(OBJSDIR)/%.o)
DEPENDSDIR  = srcs/depends
DEPENDS     = $(SRCS:$(SRCSDIR)/%.cpp=$(DEPENDSDIR)/%.d)
# 添加-MMD -MP自动生成依赖,-MMD生成不含系统头文件的依赖,-MP避免头文件删除时出错
CPPFLAGS    = -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -MMD -MP
LDFLAGS     = -lstdc++

all: $(NAME)

$(NAME): $(OBJS)
    c++ $(LDFLAGS) $^ -o $@

# 编译.o时,通过-MF指定依赖文件输出到DEPENDSDIR
$(OBJSDIR)/%.o: $(SRCSDIR)/%.cpp | $(OBJSDIR) $(DEPENDSDIR)
    c++ $(CPPFLAGS) -c $< -o $@ -MF $(DEPENDSDIR)/$*.d

$(OBJSDIR) $(DEPENDSDIR):
    mkdir -p $@

-include $(DEPENDS)

clean:
    $(RM) -rv $(OBJSDIR) $(DEPENDSDIR) 

fclean: clean
    $(RM) $(NAME)

re: fclean all

.PHONY: all clean fclean re

方案说明

  • 使用-MMD -MP编译器选项,自动生成依赖文件,无需单独写%.d规则。
  • 通过-MF $(DEPENDSDIR)/$*.d指定依赖文件的输出目录,保持文件结构整洁。
  • 每次编译.o文件时会同步生成对应的.d文件,make re执行fclean后,重新编译.o时会自动生成新的依赖文件,彻底避免原规则的时机问题。

内容的提问来源于stack exchange,提问作者Hiromasa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 04:20:19