以下 Makefile 基于正点原子的 linux 教程编写理解,个人感觉对于一个新人这样理解 Makefile 可能更容易一些,当然我就是个新人,仅供参考。
# 这里可以理解成定义了一些编译工具的宏
CROSS_COMPILE ?= arm-linux-gnueabihf-
GCC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
# 终极目标文件 名字 的宏定义
TARGET ?= bsp_beep
# 包含了整个工程的 .h 头文件
INCDIRS := imx6ull \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep
# 包含了整个工程的 .c 和 .s 文件
SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep
# 通过函数 patsubst 给集合变量 INCDIRS 里的所有头文件目录添加一个“-I”,相当于指定了目录的头文件
# Makefile 语法要求指明头文件目录的时候需要加上“-I”。
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
#if
# 准备给后面需要生成的所有 .o 文件分配目录
# 把 SRCDIRS 中的所有 .c 和 .s 文件全部通过 foreach 关键字放到 dir 中
# (wildcard 用来声明后面的 *.s 中的 * 是通配符的意思,否则 * 就是 * )
# 识别出的所有 .s 和 .c 全部放到 SFILES 和 CFILES 中,方便为之后生成的 .o 文件分配目录
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.s))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
# 使用 notdir 把 SFILES 和 CFILES 中的文件的路径去掉,以方便以后分配到指定路径
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
# 将编译后的汇编 .o 文件放到 SOBJS 里面,C语言的 .o 文件放到 COBJS里;并把所有的 .o 文件放到 obj 目录下
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.s=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
# 所有 .o 文件目录分配结束
#endif
# OBJS 用来存放所有的 .o 文件
OBJS := $(SOBJS) $(COBJS)
# 指定 Makefile 编译时需要的 .s 和 .c源文件的路径
VPATH := $(SRCDIRS)
# Makefile 需要生成的终极目标 $(TARGET).bin 的编译链接过程
$(TARGET).bin : $(OBJS)
$(LD) -Timx6ull.lds -o $(TARGET).elf $^
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
# 静态模式 [obj/%.o] 指定了 $(SOBJS) 和 $(COBJS) 中都是以 .o 结尾的文件,并且最后生成的文件都存放到 obj 目录下
# 而对于 %.o 集合里的文件又依赖于 %.s 和 .c 结尾的文件集合
$(SOBJS) : obj/%.o : %.s
$(GCC) -Wall -nostdlib -c $(INCLUDE) -o $@ $<
$(COBJS) : obj/%.o : %.c
$(GCC) -Wall -nostdlib -c $(INCLUDE) -o $@ $<
# 伪目标的定义
.PHONY: clean
clean:
rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).dis $(OBJS)
# 打印信息
print:
@echo OBJS = $(OBJS)