makefile文件如下
ROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= bsp
1、2两行是两个变量,第一行是编译器的选择,以后用其它编译器就可以直接替换第一行, 第二行是目标,一般是我们要生成的文件
ROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= ledc
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
4-7行就分别是后面要用到生成命令的前缀,cc是生成.o文件命令的前缀,链接文件的前缀ld,转换成2进制文件的前缀,以及反汇编文件的前缀
ROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= ledc
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
INCUDIRS := imx6ul \
bsp/clk \
bsp/led \
bsp/delay
SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay
\ 是下面部分与当前行是同一行,写成多行是看上去比较清爽,9-17行就分别是头文件和源文件的路径分别是变量INCUDIRS 和SRCDIRS 。
头文件的编译需要在前面加一行-I,可以使用makefile中的patsubst函数进行添加,函数的使用也是用 $(函数名)进行使用
INCLUDE := $(patsubst %, -I %, $(INCUDIRS))
$(patsubst)是使用函数,第一个%表示匹配任意长度的字符串,第二个参数是-I %可以理解为将第一个%匹配到的字符串前面加上-I, $(INCUDIRS)这是patsubst 函数在最后一个参数表示匹配的单词(以空格、tab、回车、换行分隔),INCUDIRS里面包含头文件路径,那么执行后该语句为
INCLUDE = -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay
foreach 函数是循环将$(SRCDIRS)中的单词(字符串逐个取出)放到dir里面,wildcard函数表示通配的意思,那么SFILES 就是依次(循环)取出SRCDIRS中单词(这里就是依次取出路径),取到路径后wildcard 函数通配该路径下所有的.s文件,CFILED 同理
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.s)
CFILED := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c)
匹配到的结果
SFILES = project/start.s
CFILED = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_delay.c
整个makefile现在是这样的
ROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= bsp
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
INCUDIRS := imx6ul \
bsp/clk \
bsp/led \
bsp/delay
SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay
INCLUDE := $(patsubst %, -I %, $(INCUDIRS))
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.s))
CFILED := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILED))
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.s=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.s=.o))
OBJS := $(SOBJS)$(COBJS)
19-30行
$(notdir $(SFILES))是去掉SFILES中的dir,上面dir就是路径,那么得出的就是各种.c和.s文件,SOBJS变量就是将匹配到的.s文件变成.o文件然后加上obj前缀,其实就是将后面所有.o文件放到obj目录下,OBJS就是所有.o文件的名字
VPATH := $(SRCDIRS)
在一些大的工程中,有大量的源文件,通常做法是把这些源文件分类,并存放在不同的目录中。当make需要去寻找文件的依赖关系的时候,可以在文件前加上路径,但最好的方法就是把一个路径告诉make,让make自动去找。
VPATH 就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么make就会在当前目录找不到的情况下,到指定的目录中去找寻文件。
最终makefile
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= bsp
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
INCUDIRS := imx6ul \
bsp/clk \
bsp/led \
bsp/delay
SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay
INCLUDE := $(patsubst %, -I %, $(INCUDIRS))
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.s))
CFILED := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILED))
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.s=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)
VPATH := $(SRCDIRS)
.PHONY:clean
$(TARGET).bin : $(OBJS)
$(LD) -Timx6ul.lds -o $(TARGET).elf $^
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
$(SOBJS) : obj/%.o:%.s
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
$(COBJS) : obj/%.o:%.c
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
clean:
rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).dis $(OBJS)
print:
@echo INCLUDE = $(INCLUDE)
@echo SFILES = $(SFILES)
@echo CFILED = $(CFILED)
@echo SFILENDIR = $(SFILENDIR)
@echo CFILENDIR = $(CFILENDIR)
@echo SOBJS = $(SOBJS)
@echo COBJS = $(COBJS)
@echo OBJS = $(OBJS)
@echo VPATH = $(VPATH)