如何让Make识别目录?通用Makefile规则与输出目录配置问询
针对你遇到的Makefile编写痛点——手动写依赖太繁琐、目标文件管理混乱且重复编译的问题,结合你的目录结构,我给你整理一套实用的解决方案:
首先先明确你的目录结构:
source/ |-Makefile |-a.c |-b.c |-c.c include/ |-arch1/ |-arch2/ |-common/ |-arch1-c_files/
1. 用通配符编写通用规则 + 自动生成头文件依赖
手动枚举每个.c对应的头文件确实效率极低,咱们可以借助GCC的自动依赖生成功能,搭配Make的通配符特性来实现通用规则,彻底解放双手。
先在source/Makefile里定义基础变量,把通用配置抽离出来:
# 配置头文件搜索路径,覆盖include下所有子目录 CFLAGS := -I../include -I../include/arch1 -I../include/arch2 -I../include/common -I../include/arch1-c_files # 定义目标文件输出目录,比如统一放到上级目录的obj文件夹里 OBJDIR := ../obj # 自动扫描source目录下所有.c文件 SRCS := $(wildcard *.c) # 把每个.c文件映射到OBJDIR下对应的.i文件 TARGETS := $(patsubst %.c,$(OBJDIR)/%.i,$(SRCS))
接下来编写通用规则,同时自动生成依赖文件(避免手动维护头文件依赖):
# 确保输出目录存在,不存在就创建 $(OBJDIR): mkdir -p $@ # 通用的%.i生成规则:匹配所有.c文件,生成对应路径的.i文件 $(OBJDIR)/%.i: %.c | $(OBJDIR) # 生成预处理文件(.i) gcc $(CFLAGS) -E $< -o $@ # 用GCC自动生成该.c文件的头文件依赖,保存到.d文件 gcc $(CFLAGS) -MM $< > $(OBJDIR)/$*.d # 修正依赖文件里的目标路径(因为我们把.i放到了OBJDIR,不是当前目录) sed -i 's/^\(.*\)\.o:/$(OBJDIR)\/\1.i:/' $(OBJDIR)/$*.d # 引入所有自动生成的.d依赖文件,Make会自动识别头文件变化 -include $(patsubst %.c,$(OBJDIR)/%.d,$(SRCS)) # 默认目标:生成所有.i文件 all: $(TARGETS)
这样做的核心优势:
- 不用手动写任何头文件依赖,GCC会自动扫描
#include的所有文件并生成依赖关系 - 通配符规则
$(OBJDIR)/%.i: %.c会自动匹配所有source下的.c文件,无需逐个编写规则
2. 目标文件分目录存放 + 避免重复编译
上面的规则已经把所有.i文件统一放到../obj目录下,Make的核心机制就是对比源文件/依赖文件和目标文件的修改时间——只有当源文件(或它依赖的头文件)比目标文件新时,才会重新编译,完全避免不必要的重复编译。
如果你的需求是把不同的.c文件输出到不同的子目录(比如按架构划分,a.c输出到obj/arch1,c.c输出到obj/arch2),可以调整规则如下:
# 按架构划分输出目录 OBJDIR_ARCH1 := ../obj/arch1 OBJDIR_ARCH2 := ../obj/arch2 # 手动划分不同架构对应的源文件(可根据实际情况调整) SRCS_ARCH1 := a.c b.c SRCS_ARCH2 := c.c # 映射对应架构的.i目标文件 TARGETS_ARCH1 := $(patsubst %.c,$(OBJDIR_ARCH1)/%.i,$(SRCS_ARCH1)) TARGETS_ARCH2 := $(patsubst %.c,$(OBJDIR_ARCH2)/%.i,$(SRCS_ARCH2)) # 创建所有需要的输出目录 $(OBJDIR_ARCH1) $(OBJDIR_ARCH2): mkdir -p $@ # arch1专属的通用规则 $(OBJDIR_ARCH1)/%.i: %.c | $(OBJDIR_ARCH1) gcc $(CFLAGS) -E $< -o $@ gcc $(CFLAGS) -MM $< > $(OBJDIR_ARCH1)/$*.d sed -i 's/^\(.*\)\.o:/$(OBJDIR_ARCH1)\/\1.i:/' $(OBJDIR_ARCH1)/$*.d # arch2专属的通用规则 $(OBJDIR_ARCH2)/%.i: %.c | $(OBJDIR_ARCH2) gcc $(CFLAGS) -E $< -o $@ gcc $(CFLAGS) -MM $< > $(OBJDIR_ARCH2)/$*.d sed -i 's/^\(.*\)\.o:/$(OBJDIR_ARCH2)\/\1.i:/' $(OBJDIR_ARCH2)/$*.d # 引入所有依赖文件 -include $(patsubst %.c,$(OBJDIR_ARCH1)/%.d,$(SRCS_ARCH1)) -include $(patsubst %.c,$(OBJDIR_ARCH2)/%.d,$(SRCS_ARCH2)) # 默认目标:生成所有架构的.i文件 all: $(TARGETS_ARCH1) $(TARGETS_ARCH2)
现在,不同架构的源文件会输出到各自的目录中,而且只有当某个.c文件或它依赖的头文件有更新时,才会重新生成对应的.i文件,未修改的文件不会重复编译。
内容的提问来源于stack exchange,提问作者Vishwajith.K
相关产品推荐
相关产品推荐

