如何编写Makefile编译不同子目录下的多个源文件?
批量编译多目录源文件的Makefile实现方案
核心思路
不用手动逐个指定源文件,通过Makefile内置函数自动抓取子目录下的所有源文件,配合通用规则完成批量编译,核心用到以下几个特性:
wildcard:自动匹配指定目录下的目标文件- 路径替换:将源文件路径转换为对应的目标文件路径
vpath:指定源文件的搜索路径(可选,根据目标文件存放位置决定)
方案1:目标文件统一放到obj目录(推荐)
这种方式把编译生成的.o文件集中存放在根目录的obj文件夹下,保持源文件目录整洁。完整Makefile示例:
# 定义编译器和编译参数 CC := gcc CFLAGS := -Wall -Wextra -g # 自动抓取Mcal和Ecual目录下的所有.c文件 SRC_FILES := $(wildcard Mcal/*.c Ecual/*.c) # 将源文件路径转换为obj目录下对应的.o文件路径(保留子目录结构) OBJ_FILES := $(addprefix obj/, $(SRC_FILES:.c=.o)) # 最终生成的可执行文件名称 TARGET := my_project # 指定make搜索.c文件的目录 vpath %.c Mcal Ecual # 默认执行目标:生成可执行文件 all: $(TARGET) # 链接所有.o文件生成可执行文件 $(TARGET): $(OBJ_FILES) $(CC) $(CFLAGS) $^ -o $@ # 通用编译规则:编译.c文件为对应路径的.o文件 obj/%.o: %.c $(CC) $(CFLAGS) -c $< -o $@ # 确保obj的子目录存在(编译前自动创建) obj/Mcal obj/Ecual: mkdir -p $@ # 清理中间文件和可执行文件 clean: rm -rf obj $(TARGET) # 声明伪目标,避免与同名文件冲突 .PHONY: all clean
关键部分解释:
wildcard Mcal/*.c Ecual/*.c:自动扫描两个子目录下的所有.c文件,无需手动逐个添加。addprefix obj/, $(SRC_FILES:.c=.o):把每个源文件(比如Mcal/uart.c)转换成obj/Mcal/uart.o,保留子目录结构方便管理。vpath %.c Mcal Ecual:告诉make,当需要查找.c文件时,去这两个目录搜索,确保通用规则能匹配到子目录里的源文件。obj/Mcal obj/Ecual::编译前自动创建所需的目标目录,避免因目录不存在导致编译失败。
方案2:目标文件与源文件同目录
如果不需要单独存放中间文件,可以直接在源文件所在目录生成.o文件,Makefile会更简洁:
CC := gcc CFLAGS := -Wall -Wextra -g # 抓取所有子目录下的.c文件 SRC_FILES := $(wildcard Mcal/*.c Ecual/*.c) # 直接将.c替换为.o,目标文件与源文件同目录 OBJ_FILES := $(SRC_FILES:.c=.o) TARGET := my_project all: $(TARGET) # 链接生成可执行文件 $(TARGET): $(OBJ_FILES) $(CC) $(CFLAGS) $^ -o $@ # 通用规则:匹配任意路径下的.o和对应的.c %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ # 清理命令 clean: rm -rf $(OBJ_FILES) $(TARGET) .PHONY: all clean
这种方案中,%.o: %.c规则可以直接匹配Mcal/xxx.o依赖Mcal/xxx.c,因为路径是完整的,make会自动识别对应关系,不需要额外指定搜索路径。
内容的提问来源于stack exchange,提问作者Nabil Yasser
相关产品推荐
相关产品推荐

