Makefile语法汇总
一、下面是一个最简单的Makefile的编译规则,编译的文件有main.c和input.c文件。
main : main.o input.o
gcc -o main main.o input.o
main.o : main.c
gcc -c main.c
input.o : input.c
gcc -c input.c
clean :
rm *.o main
二、语法
1、makefile的变量
#Makefile 变量的使用
2 objects = main.o input.o calcu.o
3 main: $(objects)
4 gcc -o main $(objects)
2、赋值符
- 赋值符号 = 只是取决于最后一次赋值的值。
- 赋值符号 := 不会使用后面定义的,只会只用前面定义好的。
- 赋值符号 ?= 表示变量前面没有被赋值,那么变量就被后面赋值,如果前面已经赋值过了,就使用前面赋的值。
- 变量追加 +=
objects = main.o inpiut.o objects += calcu.o
3.模式规则
使用%为通配符,可以表示所有的.o文件和.c文件
%.o : %.c
命令
4.Makefile自动化变量
自动化变量 | 描述 |
---|---|
$@ | 规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模式中定义的目标集合。 |
$% | 当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件,那么其值为空。 |
$< | 依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么“$<”就是符合模式的一系列的文件集合。 |
$? | 所有比目标新的依赖目标集合,以空格分开。 |
$^ | 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,“$^”会去除重复的依赖文件,值保留一份。 |
$+ | 和“$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。 |
$* | 这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模式为 a.%.c,那么“$*”就是 test/a.test。 |
5、伪目标
当工程文件中有clean的文件,make clean命令将失效,这时定义clean为伪目标可以避免该类问题的出现。
.PHONY : clean
clean:
rm *.o
rm main
三、Makefile进阶
通过上面的语法介绍,第一节中的Makefile可以修改成如下
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
%.o : %.c
gcc -c $<
.PHONY : clean
clean:
rm *.o
rm main
四、Makefile函数的使用
一、subst
函数功能为字符串text中的from内容替换为to。
$(subst <from>,<to>,<text>)
#使用方法如下
$(subst lidong,LIDONG,my name is lidong)
二、patsubst
此函数查找text是否符合pattern的模式,如果符合就全部替换成replacement。
$(patsubst <pattern>,<replacement>,<text>)
#使用方法如下
$(patsubst %.c, %.o , a.c b.c c.c)
将字符串“a.c b.c c.c”中的所有符合“%.c”的字符串,替换为“%.o”,替换完成以后的字符串为“a.o b.o c.o”
三、dir
函数 dir 用来获取目录。
$(dir <names…>)
#使用方法如下,提取出来的就是“/src”。
$(dir </src/a.c>)
四、notdir
去除文件中的目录部分,也就是提取文件名。
$(notdir <names…>)
#使用方法如下,提取出来的就是“a.c”。
$(notdir </src/a.c>)
五、foreach
函数循环,把参数list中的单词逐一取出来放到参数var中,然后执行text表达式,text中所包含的每个字符串会以空格隔开。
$(foreach <var>,<list>,<text>)
#如下可以依次将文件名替换成.o文件
names := a b c d
files := $(foreach n,$(names),$(n).o)
六、wildcard
获取当前目录的xx文件。
$(wildcard PATTERN…)
#获取当前目录下的所有.c文件
$(wildcard *.c)
七、通用型具备BSP代码管理的Makefile模板
#定义交叉编译器名字变量
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= bsp
#gcc编译器
CC := $(CROSS_COMPILE)gcc
#连接器
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
#头文件包含路径
INCDIRS := imx6ul \
bsp/clk \
bsp/led \
bsp/delay
#汇编文件包含路径
SRCDIRS := project \
bsp/clk \
bsp/led \
bsp/delay
#头文件路径前加-I
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
#获取所有带路径.S文件
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
#获取所有带路径.C文件
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
#获取所有.S文件
SFILENDIR := $(notdir $(SFILES))
#获取所有.C文件
CFILENDIR := $(notdir $(CFILES))
#汇编文件编译生成的.o文件放入obj/文件夹下
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
#c文件编译生成的.o文件放入obj/文件夹下
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
#所有包含路径的.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
#静态模式的写法,将所有的.s文件编译成.o放到obj目录下去
$(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).dis $(TARGET).bin $(COBJS) $(SOBJS)