Makefile执行异常问题咨询:修改目标文件后未触发重建及re目标执行报错
让我们一步步解决你遇到的两个Makefile问题:
问题1:touch libftprintf.a后make all不重建库
原因分析
你的$(NAME)目标规则写法有两个致命问题:
$(NAME): $(OBJS) $(LIB) $(NAME) $(OBJS) $(LIBFT)
- 依赖列表里重复了
$(NAME)(目标文件本身)—— Make会默认认为目标的时间戳肯定比自身新,所以永远不会触发重建逻辑。 - 这个规则没有执行命令—— Make完全不知道该如何从依赖生成
libftprintf.a,只能依赖隐含规则,但隐含规则无法处理静态库的打包逻辑。
当你touch libftprintf.a更新时间戳后,Make对比依赖时会发现目标的时间戳比所有依赖都新(甚至包括它自己),自然判定不需要任何操作。
解决方案
修正$(NAME)规则,去掉重复依赖,添加正确的静态库打包命令:
$(NAME): $(OBJS) $(LIBFT) $(LIB) $(NAME) $(OBJS) # 可选:如果需要把libft的内容合并到当前库,取消下面注释 # ar -x $(LIBFT) # $(LIB) $(NAME) *.o # rm -f *.o
$(LIB)是你定义的ar rcs,这个命令会把$(OBJS)里的目标文件打包进libftprintf.a。- 如果需要让
libftprintf.a包含libft的所有内容(避免链接时同时指定两个库),可以先解压libft的目标文件,再一起打包。
问题2:make re首次执行报错,第二次才正常
原因分析
你的原re目标写法是:
re: fclean all
Make处理这种链式目标时,会先执行fclean(删除objectives目录和库文件),再执行all。但问题出在:
$(OBJS)的规则中,$(OBJS_DIR)是order-only依赖(用|标记),加上原$(NAME)规则没有命令,导致Make的依赖解析逻辑出现时序混乱,无法正确触发$(OBJS_DIR)的创建规则。- 当你改成
re: @$(MAKE) fclean @$(MAKE) all后正常,是因为这种写法是嵌套执行Make进程—— 第一个make fclean完全执行完毕(目录被删除)后,才启动新的Make进程执行all,新进程会重新完整解析依赖,正确创建objectives目录。
解决方案
推荐采用嵌套Make的写法,彻底避免时序问题:
re: @$(MAKE) fclean @$(MAKE) all
把两个命令分开写,确保fclean完全执行后再启动all的构建,上下文完全隔离,不会出现依赖解析的混乱。
另外可以给mkdir命令加-p参数,避免目录已存在时报错,让Makefile更健壮:
$(OBJS_DIR): mkdir -p $(OBJS_DIR)
修正后的完整Makefile
NAME := libftprintf.a LIB := ar rcs CC := gcc CFLAGS := -Wall -Wextra -Werror SRCS_DIR := ./sources/ HDRS_DIR := ./headers/ OBJS_DIR := ./objectives/ SRCS_FILES := ft_conv.c \ ft_eval_hex.c \ ft_eval_number.c \ ft_eval_string.c \ ft_parsers.c \ ft_strs_join.c \ ft_eval_char.c \ ft_eval_int.c \ ft_eval_percent.c \ ft_handler.c \ ft_printf.c HDRS_FILES := ft_conv.h \ ft_eval_hex.h \ ft_eval_number.h \ ft_eval_string.h \ ft_parsers.h \ ft_strs_join.h \ ft_eval_char.h \ ft_eval_int.h \ ft_eval_percent.h \ ft_handler.h \ ft_printf.h OBJS_FILES := $(SRCS_FILES:.c=.o) SRCS := $(addprefix $(SRCS_DIR),$(SRCS_FILES)) HDRS := $(addprefix $(HDRS_DIR),$(HDRS_FILES)) OBJS := $(addprefix $(OBJS_DIR),$(OBJS_FILES)) LIBFT_DIR := ./libft/ LIBFT_NAME := libft.a LIBFT := $(addprefix $(LIBFT_DIR),$(LIBFT_NAME)) RM := rm -rf all: $(NAME) bonus: all bonus_one: all bonus_two: all $(NAME): $(OBJS) $(LIBFT) $(LIB) $(NAME) $(OBJS) # 可选:合并libft到当前库 # ar -x $(LIBFT) # $(LIB) $(NAME) *.o # rm -f *.o $(OBJS_DIR)%.o: $(SRCS_DIR)%.c $(HDRS) Makefile | $(OBJS_DIR) subsystem $(CC) $(CFLAGS) -c $< -o $@ -I $(HDRS_DIR) -I $(LIBFT_DIR) subsystem: @$(MAKE) -C $(LIBFT_DIR) $(OBJS_DIR): mkdir -p $(OBJS_DIR) clean: @$(MAKE) -C $(LIBFT_DIR) clean $(RM) $(OBJS_DIR) fclean: clean @$(MAKE) -C $(LIBFT_DIR) fclean $(RM) $(NAME) re: @$(MAKE) fclean @$(MAKE) all .PHONY: all subsystem bonus bonus_one bonus_two clean fclean re
内容的提问来源于stack exchange,提问作者lteresia
相关产品推荐
相关产品推荐

