多依赖目标文件的Makefile简化方案及执行原理问询
Makefile多目标依赖场景的问题解答
一、简化版方案是否合理?
完全合理。你用的是Makefile的仅依赖规则(只声明目标和依赖,不提供命令)加模式规则(提供通用编译命令)的组合写法,这是Make的标准用法之一。
当Make处理某个.o目标时,会自动合并所有匹配该目标的规则中的依赖,然后使用能生成该目标的模式规则里的编译命令执行编译。比如main.o的依赖来自你手动声明的main.o: main.c node.h funk2.h,而编译命令来自通用的%.o:%.c规则,两者配合完全能正确处理依赖更新和编译逻辑。
二、make命令的具体执行流程(针对你的场景)
假设你的最终目标是生成可执行文件main,Makefile结构大致如下:
main: main.o funk1.o funk2.o gcc $^ -o $@ # 仅依赖规则 main.o: main.c node.h funk2.h funk1.o: funk1.c funk1.h funk2.o: funk2.c funk2.h # 通用编译规则 %.o: %.c gcc -c $< -o $@
执行make时的流程是:
- 确定最终目标:默认执行Makefile中的第一个目标
main。 - 检查最终目标是否需要更新:对比
main和它的依赖文件main.o、funk1.o、funk2.o的修改时间,如果任意一个.o比main新,或者main不存在,就需要重新链接。 - 逐个处理每个
.o依赖:- 以
main.o为例:先读取仅依赖规则,确定它的依赖是main.c、node.h、funk2.h;然后匹配到%.o:%.c模式规则,获取编译命令。 - 检查
main.o与所有依赖文件的修改时间:如果main.o不存在,或者任意一个依赖文件的修改时间晚于main.o,就执行编译命令gcc -c main.c -o main.o。 - 同理处理
funk1.o和funk2.o,各自使用对应的仅依赖规则获取依赖,再用模式规则的命令编译。
- 以
- 链接生成最终可执行文件:所有
.o文件都处理完成后,执行链接命令gcc main.o funk1.o funk2.o -o main。
三、用单一规则处理所有目标文件的方法
有两种常用方式可以实现:
方式1:自动生成依赖(推荐)
利用GCC的-MM选项自动分析.c文件的头文件依赖,无需手动声明每个.o的依赖,仅用一个模式规则即可处理所有目标:
OBJS = main.o funk1.o funk2.o main: $(OBJS) gcc $^ -o $@ # 通用编译规则 %.o: %.c gcc -c $< -o $@ # 自动生成依赖文件(.d) %.d: %.c gcc -MM $< > $@ # 引入自动生成的依赖 include $(OBJS:.o=.d)
执行make时,会先为每个.c文件生成对应的.d文件(比如main.d里会包含main.o: main.c node.h funk2.h),include后这些依赖会被Make识别,自动处理所有.o的依赖更新。
方式2:静态模式规则+变量扩展
如果需要手动管理依赖,可以用静态模式规则结合自定义变量,把所有目标的依赖集中定义,用一个规则处理:
OBJS = main.o funk1.o funk2.o # 定义每个目标的依赖变量 main.o_DEPS = main.c node.h funk2.h funk1.o_DEPS = funk1.c funk1.h funk2.o_DEPS = funk2.c funk2.h main: $(OBJS) gcc $^ -o $@ # 静态模式规则,处理所有OBJS目标 $(OBJS): %.o: $($*_DEPS) gcc -c $< -o $@
这里$*是自动变量,代表模式匹配的前缀(比如处理main.o时,$*就是main),通过$($*_DEPS)可以自动获取对应目标的依赖列表,实现用单一规则处理所有.o目标。
内容的提问来源于stack exchange,提问作者Speedyspeedboy
相关产品推荐
相关产品推荐

