我尝试编写一个 Makefile,它应该根据需要将所有源代码编译到对象中,然后构建输出二进制文件。
我已经尝试了几个示例并找到了解决方案,但前提是我将所有源放在同一个文件夹中。
但是在这个项目中文件分布在多个目录和子目录中。
我的 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
ASM_SOURCES := $(shell find . -name "*.S")
GCC_SOURCES := $(shell find . -name "*.c")
ASM_DIRNAME := $(shell dirname $(ASM_SOURCES))
GCC_DIRNAME := $(shell dirname $(GCC_SOURCES))
ASM_OBJECTS := $(patsubst $(ASM_DIRNAME)/%.S, $(ASM_DIRNAME)/%.o, $(ASM_SOURCES))
GCC_OBJECTS := $(patsubst $(GCC_DIRNAME)/%.c, $(GCC_DIRNAME)/%.o, $(GCC_SOURCES))
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:
$(CC) $(INCLUDES) $(GCC_SOURCES) $(ASM_SOURCES) $(CFLAGS) -T $(LDSCRIPT) -o $(TARGET).elf
$(OBJCPY) $(TARGET).elf $(TARGET).bin -O binary
bad: $(GCC_OBJECTS) $(ASM_OBJECTS) \
$(GCC) $(CFLAGS) -T $(LDSCRIPT) $^ -o $(TARGET) \
$(ASM_DIRNAME)/%.o:$(ASM_DIRNAME)/%.S \
$(GCC) $(INCLUDES) $(CFLAGS) -c $< -o $@ \
$(GCC_DIRNAME)/%.o:$(GCC_DIRNAME)/%.c \
$(GCC) $(INCLUDES) $(CFLAGS) -c $< -o $@ \
clean:
rm $(TARGET).elf $(TARGET).bin $(TARGET).d output.map
使用“make”命令进行编译,然后从头开始编译所有内容。
我只想编译更改源,但是当我执行“make bad”命令时,我收到以下错误。
Makefile:50: *** mixed implicit and normal rules: deprecated syntax
arm-none-eabi-gcc -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 -c -o startup/startup_MK64F12.o startup/startup_MK64F12.c
startup/startup_MK64F12.c:88:34: fatal error: fsl_device_registers.h: No such file or directory
#include "fsl_device_registers.h"
^
compilation terminated.
<builtin>: recipe for target 'startup/startup_MK64F12.o' failed
make: *** [startup/startup_MK64F12.o] Error 1
对于经验丰富的编码专家来说,这可能是简单的事情,但我在 Makefile 世界中还是个新手。
谁能帮我找出这个 Makefile 的问题?
你的
all:
规则说“每次都编译一切”:
all:
$(CC) $(INCLUDES) $(GCC_SOURCES) $(ASM_SOURCES) $(CFLAGS) -T $(LDSCRIPT) -o $(TARGET).elf
$(OBJCPY) $(TARGET).elf $(TARGET).bin -O binary
如果文件
all
不存在,则在所有源上运行 C 编译器并创建可执行文件(但不是文件 all
)。如果文件all
存在,则什么也不会发生——all
不依赖于任何东西。
如果你不想编译所有东西,你需要告诉
make
可执行文件依赖于目标文件并链接目标文件。
我认为您需要更多类似的东西:
PROGRAM = $(TARGET).elf
all: $(PROGRAM)
$(PROGRAM): $(GCC_OBJECTS) $(ASM_OBJECTS)
$(CC) $(INCLUDES) $(GCC_OBJECTS) $(ASM_OBJECTS) $(CFLAGS) -T $(LDSCRIPT) -o $(PROGRAM)
$(OBJCPY) $(PROGRAM) $(TARGET).bin -O binary
您可能需要做一些工作才能构建目标文件,但这表示“all
depends on the program, and the program depends on the object files, and when the object files are all up to date, you build the program like this. You might want to designate
.PHONY: all` 因为它不是“真实”目标——它不是您创建的文件。
您应该使用宏来重复元素,例如
PROGRAM = $(TARGET).elf
(也可能是$(TARGET).bin
)。如果一定要多次写出来,应该是宏吧
在您的原始 Makefile 中,目标文件列表是使用
patsubst
生成的。相反,您可以使用 :=
赋值运算符直接将源文件扩展名替换为目标文件扩展名。
对目标文件使用模式规则。而不是使用
$(ASM_DIRNAME)/%.o:$(ASM_DIRNAME)/%.S
和 $(GCC_DIRNAME)/%.o:$(GCC_DIRNAME)/%.c
规则,它们会导致“混合隐式规则和正常规则”错误,您应该使用像 %.o: %.S
和 %.o: %.c
这样的模式规则。这将匹配任何.S
或.c
文件并生成相应的.o
文件。
您应该为构建
TARGET.elf
和TARGET.bin
文件创建单独的规则。 TARGET.elf
规则应该依赖于$(GCC_OBJECTS)
和$(ASM_OBJECTS)
并使用$(CC)
命令编译和链接它们。 TARGET.bin
规则应该依赖于 TARGET.elf
文件并使用 $(OBJCPY)
命令生成二进制文件。
此外,
clean
规则还应该删除生成的目标文件。使用 rm -f
命令,然后使用目标文件列表 $(ASM_OBJECTS)
和 $(GCC_OBJECTS)
.