如何使用Makefile在子目录生成C语言项目的.o目标文件
修改方案
你只需要对原有Makefile做以下几处调整即可实现需求:
- 开头声明目标文件存储目录变量,同时把重复的编译、链接参数抽成公共变量,降低维护成本
- 所有
.o目标和引用路径前统一加上目录前缀 - 编译命令末尾增加
-o $@参数,明确指定目标文件输出到指定目录 - 增加目录自动创建逻辑,避免首次编译因目录不存在报错
- 链接、清理阶段的路径同步修改
完整修改后Makefile
# 自定义目标文件存储路径,可按需调整 OBJDIR = ./objects # 公共编译参数 CFLAGS = -fstack-protector-all -std=c99 -g # 公共链接库 LDLIBS = -lm # 最终生成的可执行文件目标 progr : $(OBJDIR)/main.o $(OBJDIR)/manipulate_strings.o $(OBJDIR)/environment_set.o $(OBJDIR)/variables.o $(OBJDIR)/segments_private.o $(OBJDIR)/rectangle_private.o $(OBJDIR)/circle_private.o $(OBJDIR)/tree.o $(OBJDIR)/dynamic_list.o $(OBJDIR)/visibility.o $(OBJDIR)/query.o gcc $(CFLAGS) $^ -o $@ $(LDLIBS) # 编译完成后如果不需要保留目标文件可保留这行,无需清理则删除 rm -rf $(OBJDIR)/*.o # 各级源文件对应的.o生成规则 $(OBJDIR)/main.o : main.c manipulate_strings.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/manipulate_strings.o : manipulate_strings.c manipulate_strings.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/environment_set.o : environment_set.c environment_set.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/variables.o : private/variables.c private/variables.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(LDLIBS) $(OBJDIR)/segments_private.o : private/segments_private.c private/segments_private.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(LDLIBS) $(OBJDIR)/rectangle_private.o : private/rectangle_private.c private/rectangle_private.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/circle_private.o : private/circle_private.c private/circle_private.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/tree.o : data_struct/tree.c data_struct/tree.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/dynamic_list.o : data_struct/dynamic_list.c data_struct/dynamic_list.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/visibility.o : visibility.c visibility.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(OBJDIR)/query.o : query.c query.h @mkdir -p $(OBJDIR) gcc $(CFLAGS) -c $< -o $@ $(LDLIBS) # 可选:手动清理目标 clean: rm -rf $(OBJDIR) progr
可选简化优化
如果不想重复写每个.o的编译规则,可以添加模式规则统一处理,之后只需要维护每个.o的头文件依赖即可:
# 匹配根目录的.c文件生成.o $(OBJDIR)/%.o : %.c @mkdir -p $(@D) gcc $(CFLAGS) -c $< -o $@ # 匹配private目录的.c文件生成.o $(OBJDIR)/%.o : private/%.c @mkdir -p $(@D) gcc $(CFLAGS) -c $< -o $@ # 匹配data_struct目录的.c文件生成.o $(OBJDIR)/%.o : data_struct/%.c @mkdir -p $(@D) gcc $(CFLAGS) -c $< -o $@
说明
- 原有Makefile存在一处笔误:
progr的依赖列表中写的是segment_private.o,实际对应源文件是segments_private.c,上述代码已经修正该问题 mkdir -p命令不会在目录已存在时报错,适合编译前自动创建目录$<代表第一个依赖文件,$@代表当前目标文件,属于Makefile内置自动变量,可简化代码编写
内容的提问来源于stack exchange,提问作者Komarchewski
相关产品推荐
相关产品推荐

