Makefile问题:单文件修改触发不同目录源文件全量重编译
我来帮你搞定这个增量编译的问题!你现在遇到的核心问题是当前Makefile的目标依赖关系没有正确对应到输出目录的.o文件,导致Make无法追踪哪些文件已经更新,每次修改单个源文件都会触发全量编译。下面是修正后的Makefile,以及详细的修改说明:
修正后的Makefile
NAME=Program CC=arm-none-eabi-gcc CFLAGS=-c -Wall -O0 -std=c99 \ -nostartfiles --specs=nano.specs \ -mthumb -fmessage-length=0 \ -fsigned-char -ffunction-sections \ -fdata-sections -mcpu=cortex-m0 BID?=_DEV DEFINES= -DPROD -DBLD_ID=\"$(BID)\" LDFLAGS= -nostartfiles INCLUDES= -ISrc/App/Include -ISrc/Device/CMSIS/Include SOURCES= Src/main.c Src/App/Source/Application.c Src/App/Source/EOL.c Src/Svc/Source/TimerManager.c # 直接将源文件转换为输出目录下的.o文件 OBJDIR=Output OBJECTS=$(addprefix $(OBJDIR)/,$(notdir $(SOURCES:.c=.o))) .PHONY: all rebuild clean all: $(OBJDIR) $(OBJDIR)/$(NAME).hex # 生成hex依赖elf $(OBJDIR)/%.hex: $(OBJDIR)/%.elf arm-none-eabi-objcopy -O ihex $< $@ # 链接elf依赖所有输出目录下的.o文件 $(OBJDIR)/$(NAME).elf: $(OBJECTS) $(CC) $(LDFLAGS) $^ -o $@ # 为不同路径的.c文件编写编译规则 $(OBJDIR)/%.o: Src/%.c $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ $(OBJDIR)/%.o: Src/App/Source/%.c $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ $(OBJDIR)/%.o: Src/Svc/Source/%.c $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -o $@ $(OBJDIR): mkdir -p $(OBJDIR) rebuild: clean all clean: rm -rf $(OBJDIR)
关键修改点说明
正确定义目标文件路径
原来的OBJECTS定义绕了多层映射,现在直接通过addprefix和notdir把所有源文件直接映射到OBJDIR下的.o文件,让Make能准确追踪每个.o的依赖关系。明确源文件到输出目录.o的对应规则
原来的.c.o通用规则会把输出写到OBJDIR,但Make默认追踪的是当前目录的.o文件,导致每次都认为.o不存在,必须重新编译。现在我们为不同路径的源文件编写了明确的规则,比如$(OBJDIR)/%.o: Src/App/Source/%.c,让Make清楚知道:Output/Application.o依赖于Src/App/Source/Application.c,只有当源文件修改时才会重新编译这个.o。修正链接和生成hex的目标路径
把.elf和.hex的目标都放到OBJDIR下,保持所有输出文件统一存放,同时让整个依赖链更清晰。优化clean命令
用rm -rf $(OBJDIR)直接删除整个输出目录,比逐个删除文件更干净高效,也避免遗漏文件。
现在你修改单个源文件(比如main.c),只会重新编译main.c生成Output/main.o,然后重新链接elf文件,不会触发其他未修改文件的编译;当没有文件修改时,Make会提示make: Nothing to be done for 'all'.,完全符合你的需求。
内容的提问来源于stack exchange,提问作者user1785853

