使用Makefile避免编译未修改源码的问题求助
多目录源码Makefile编译目标文件失败问题解决
问题背景
需要编写适配多目录及子目录源码的Makefile,将所有源码编译为目标文件后链接生成二进制文件。当前make all可正常完成编译,但执行make bad时会报错。原始Makefile通过手动列举所有源文件实现多目录编译,修改后尝试自动查找所有.c和.S文件,但目标文件的编译规则存在问题。
错误原因分析
- 目录变量处理错误:使用
ASM_DIRNAME := $(shell dirname $(ASM_SOURCES))和GCC_DIRNAME := $(shell dirname $(GCC_SOURCES))时,若存在多目录源文件,dirname会返回空格分隔的多个目录路径,导致后续patsubst和模式规则(如$(ASM_DIRNAME)/%.o: $(ASM_DIRNAME)/%.S)变成无效的多目录拼接格式,Make无法匹配正确的文件路径。 - 变量引用错误:
bad目标中使用了未定义的$(GCC)变量,正确应使用已定义的$(CC);链接输出文件名与all目标的$(TARGET).elf不一致,且编译目标文件时缺少头文件路径INCLUDES。 - 模式规则不通用:原规则仅针对单一目录设计,无法适配多目录下的源文件编译。
修正后的Makefile
TARGET=analyser CC=arm-none-eabi-gcc OBJCPY=arm-none-eabi-objcopy CFLAGS= -DNDEBUG -DCPU_MK64FN1M0VLL12 -DUSE_RTOS=1 -DPRINTF_ADVANCED_ENABLE=1 \ -DFRDM_K64F -DFREEDOM -DFSL_RTOS_FREE_RTOS -Os -Wall -fno-common \ -ffunction-sections -fdata-sections -ffreestanding -fno-builtin \ -mthumb -mapcs -std=gnu99 -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MMD -MP \ --specs=nano.specs --specs=nosys.specs -Wall -fno-common -ffunction-sections \ -fdata-sections -ffreestanding -fno-builtin -mthumb -mapcs -Xlinker --gc-sections \ -Xlinker -static -Xlinker -z -Xlinker muldefs -Xlinker -Map=output.map -mcpu=cortex-m4 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Xlinker --defsym=__stack_size__=2048 -Xlinker \ --defsym=__heap_size__=25600 -Wall LDSCRIPT=linker/MK64FN1M0xxx12_flash.ld # 自动查找所有.c和.S文件 ASM_SOURCES := $(shell find . -name "*.S") GCC_SOURCES := $(shell find . -name "*.c") # 将源文件路径替换为对应的目标文件路径 ASM_OBJECTS := $(ASM_SOURCES:.S=.o) GCC_OBJECTS := $(GCC_SOURCES:.c=.o) INCLUDES=\ -Iapp/include \ -ICMSIS \ -Ifsl \ -IFreeRTOS/include \ -IFreeRTOS/include/private \ -IFreeRTOS/src/portable/GCC/ARM_CM4F \ -Iinclude \ -Idrivers/uart \ -Idrivers/serial_manager \ -Idrivers/lists \ -Ilwip/port \ -Ilwip/src \ -Ilwip/src/include \ all: $(TARGET).elf $(TARGET).bin # 直接编译所有源文件生成elf $(TARGET).elf: $(CC) $(INCLUDES) $(GCC_SOURCES) $(ASM_SOURCES) $(CFLAGS) -T $(LDSCRIPT) -o $@ $(TARGET).bin: $(TARGET).elf $(OBJCPY) $< $@ -O binary # 通过目标文件链接生成elf bad: $(TARGET).elf $(TARGET).elf: $(GCC_OBJECTS) $(ASM_OBJECTS) $(CC) $(CFLAGS) -T $(LDSCRIPT) $^ -o $@ # 通用模式规则:编译任意目录下的.c文件为.o %.o: %.c $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@ # 通用模式规则:编译任意目录下的.S文件为.o %.o: %.S $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@ clean: rm -f $(TARGET).elf $(TARGET).bin $(TARGET).d output.map $(GCC_OBJECTS) $(ASM_OBJECTS)
关键修正点
- 目标文件路径生成:直接使用
$(ASM_SOURCES:.S=.o)和$(GCC_SOURCES:.c=.o)将每个源文件替换为同目录下的目标文件,无需手动提取目录。 - 通用模式规则:使用
%.o: %.c和%.o: %.S匹配任意目录下的源文件,自动生成对应的目标文件。 - 修正
bad目标:将$(GCC)改为$(CC),统一输出文件名为$(TARGET).elf,并依赖所有目标文件完成链接。 - 增强
clean目标:添加删除所有目标文件的命令,确保清理彻底。
内容的提问来源于stack exchange,提问作者IceDefcon
相关产品推荐
相关产品推荐

