Makefile⽣成.d头⽂件依赖规则
下⾯是以我写的实际项⽬中的测试程序的Makefile为例进⾏说明
我们可以把要⽣成.d⽂件的gcc指令单独做成⼀个规则,如下$(OBJS_DIR)/%.d:%.c
CC:=gcc
CFLAGS:=-std=gnu99 -g
LDFLAGS:= -lpthread
OBJS_DIR:=./objs
MEIHE_SRCS:= mt_test_meihe.c ry_hj_frame.c CL_PduCtrl.c OSAL_Error.c mt_tcp_parse.c
MEIHE_OBJS:=$(addprefix ${OBJS_DIR}/, $(MEIHE_SRCS:.c=.o))
MEIHE_DEPS=$(patsubst %.o, %.d, $(MEIHE_OBJS))
MEIHE_OUTPUT:=./mt_meihe
.
PHONY: clean
build: mk-dirs $(MEIHE_OUTPUT)
$(MEIHE_OUTPUT):$(MEIHE_OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
$(OBJS_DIR)/%.o: %.c
$(CC) -I./ -c $< -o $@ $(CFLAGS)
$(OBJS_DIR)/%.d:%.c
$(CC) $< -MM -MF $(OBJS_DIR)/$*.d -MP
mk-dirs:
if [ ! -d $(OBJS_DIR) ] ; then mkdir -p $(OBJS_DIR); fi
clean:
rm -rf $(OBJS_DIR)/* $(MEIHE_OUTPUT)
include $(MEIHE_DEPS)
运⾏结果为:
test_mk:30: objs/mt_test_meihe.d: No such file or directory
test_mk:30: objs/ry_hj_frame.d: No such file or directory
test_mk:30: objs/CL_PduCtrl.d: No such file or directory
test_mk:30: objs/OSAL_Error.d: No such file or directory
test_mk:30: objs/mt_tcp_parse.d: No such file or directory
gcc mt_tcp_parse.c -MM -MF ./objs/mt_tcp_parse.d -MP
gcc OSAL_Error.c -MM -MF ./objs/OSAL_Error.d -MP
gcc CL_PduCtrl.c -MM -MF ./objs/CL_PduCtrl.d -MP
gcc ry_hj_frame.c -MM -MF ./objs/ry_hj_frame.d -MP
gcc mt_test_meihe.c -MM -MF ./objs/mt_test_meihe.d -MP
if [ ! -d ./objs ] ; then mkdir -p ./objs; fi
gcc -I./ -c mt_test_meihe.c -o objs/mt_test_meihe.o -std=gnu99 -g
gcc -I./ -c ry_hj_frame.c -o objs/ry_hj_frame.o -std=gnu99 -g
gcc -I./ -c CL_PduCtrl.c -o objs/CL_PduCtrl.o -std=gnu99 -g
gcc -I./ -c OSAL_Error.c -o objs/OSAL_Error.o -std=gnu99 -g
gcc -I./ -c mt_tcp_parse.c -o objs/mt_tcp_parse.o -std=gnu99 -g
gcc -o mt_meihe objs/mt_test_meihe.o objs/ry_hj_frame.o objs/CL_PduCtrl.o objs/OSAL_Error.o objs/mt_tcp_parse.o -lpthread
可以看到,include刚开始没有到各个.d⽂件,然后发现Makefile中有⽣成.d⽂件的规则,所以调⽤规则⽣成.d⽂件。
⽣成规则的指令如下:error parse new
gcc mt_tcp_parse.c -MM -MF ./objs/mt_tcp_parse.d -MP
gcc OSAL_Error.c -MM -MF ./objs/OSAL_Error.d -MP
gcc CL_PduCtrl.c -MM -MF ./objs/CL_PduCtrl.d -MP
gcc ry_hj_frame.c -MM -MF ./objs/ry_hj_frame.d -MP
gcc mt_test_meihe.c -MM -MF ./objs/mt_test_meihe.d -MP
-MM 参数⽤于⽣成⽂件的依赖关系,和 -M 类似,但不包含标准库的头⽂件
-MF 参数⽤于指定,依赖关系输出到哪个⽂件,
-MP ⽣成的依赖⽂件⾥⾯,依赖规则中的所有.h依赖项都会在该⽂件中⽣成⼀个伪⽬标,其不依赖任何其他依赖项。该伪规则将避免删除了对应的头⽂件⽽没有更新 “Makefile” 去匹配新的依赖关系⽽导致make出错的情况出现。任意⼀个.d⽂件,
CL_PduCtrl.d⽂件如下;
CL_PduCtrl.o: CL_PduCtrl.c CL_PduCtrl.h OSAL_Comdef.h OSAL.h
CL_PduCtrl.h:
OSAL_Comdef.h:
OSAL.h:
我⾃⼰的理解,这些伪⽬标是否除了上述的⽤途,还可以⽤于防⽌Makefile寻隐式规则去匹配头⽂件,提⾼效率,但参考其他开源⼯程(这⾥参考u-boot顶层Makefile,332⾏)⾥⾯防⽌隐式规则起作⽤的语法,应该在后⾯加分好格式如下:
scripts/Kbuild.include: ;
include scripts/Kbuild.include
另外,此时的gcc命令,只⽤于⽣成.d⽂件,⼀般⽤的时候可以.d⽂件和.o⽂件⼀起⽣成,不⽤将⽣成.d⽂件的⽬标单独列出来,你可能会想,那第⼀次编译的时候,还没有⽣成.d⽂件,会不会不严谨,其实第⼀次编译的时候完全可以不⽤.d⽂件,.d⽂件是给后续修改头⽂件后,再去编译⼯程使⽤的。 另外仔细想想,其实如果.c⽂件中#include语句,增加新的头⽂件或者删除旧的头⽂件( -MP参数,⽣成的头⽂件伪⽬标可以保证不出错)也不会出错。将上述Makefile修改如下:
CC:=gcc
CFLAGS:=-std=gnu99 -g
LDFLAGS:= -lpthread
OBJS_DIR:=./objs
MEIHE_SRCS:= mt_test_meihe.c ry_hj_frame.c CL_PduCtrl.c OSAL_Error.c mt_tcp_parse.c
MEIHE_OBJS:=$(addprefix ${OBJS_DIR}/, $(MEIHE_SRCS:.c=.o))
MEIHE_DEPS=$(patsubst %.o, %.d, $(MEIHE_OBJS))
MEIHE_OUTPUT:=./mt_meihe
.PHONY: clean
build: mk-dirs $(MEIHE_OUTPUT)
$(MEIHE_OUTPUT):$(MEIHE_OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
$(OBJS_DIR)/%.o: %.c
$(CC) -I./ -c $< -o $@ $(CFLAGS) -MD -MF $(OBJS_DIR)/$*.d -MP
mk-dirs:
if [ ! -d $(OBJS_DIR) ] ; then mkdir -p $(OBJS_DIR); fi
clean:
rm -rf $(OBJS_DIR)/* $(MEIHE_OUTPUT)
-include $(MEIHE_DEPS)
将规则$(OBJS_DIR)/%.d:%.c删除,$(OBJS_DIR)/%.o: %.c修改如下
$(OBJS_DIR)/%.o: %.c
$(CC) -I./ -c $< -o $@ $(CFLAGS) -MD -MF $(OBJS_DIR)/$*.d -MP
include $(MEIHE_DEPS)修改为-include $(MEIHE_DEPS)
输出结果如下:
if [ ! -d ./objs ] ; then mkdir -p ./objs; fi
gcc -I./ -c mt_test_meihe.c -o objs/mt_test_meihe.o -std=gnu99 -g -MD -MF ./objs/mt_test_meihe.d -MP
gcc -I./ -c ry_hj_frame.c -o objs/ry_hj_frame.o -std=gnu99 -g -MD -MF ./objs/ry_hj_frame.d -MP
gcc -I./ -c CL_PduCtrl.c -o objs/CL_PduCtrl.o -std=gnu99 -g -MD -MF ./objs/CL_PduCtrl.d -MP
gcc -I./ -c OSAL_Error.c -o objs/OSAL_Error.o -std=gnu99 -g -MD -MF ./objs/OSAL_Error.d -MP
gcc -I./ -c mt_tcp_parse.c -o objs/mt_tcp_parse.o -std=gnu99 -g -MD -MF ./objs/mt_tcp_parse.d -MP
gcc -o mt_meihe objs/mt_test_meihe.o objs/ry_hj_frame.o objs/CL_PduCtrl.o objs/OSAL_Error.o objs/mt_tcp_parse.o -lpthread
可以看到此时的gcc命令是同时⽣成.o⽂件以及.d⽂件,此时gcc的参数从 -MM换成了-MD,还增加了
其他⽤于⽣成.o⽂件的选项。
-MD参数也⽤于⽣成⽂件的依赖关系,但不会阻⽌编译过程,-M 或者-MM会在预编译阶段结束后⾃动停⽌,但是-MD不会停⽌,会继续编译成成.o⽂件。其实这⾥最好⽤-MMD,-MD参数和-M参数⼀样也会将标准头⽂件也列⼊依赖关系。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论