Makefile 规则格式
命令列表中的每条命令必须以 TAB 键开始,不能使用空格!
目标…... : 依赖文件集合……
命令 1
命令 2
……
Make 的执行过程:
1. make 命令会在当前目录下查找以 Makefile(makefile 其实也可以)命名的文件。
2. 当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件
3. 当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比
目标文件晚)的话就会执行后面的命令来更新目标
Makefile 变量
1 #Makefile 变量的使用
2 objects = main.o input.o calcu.o
3 main: $(objects)
4 gcc -o main $(objects)
变量的引用方法是“$(变量名)”,
=
使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值
“:=”
这是因为赋值符“:=”
不会使用后面定义的变量,只能使用前面已经定义好的,这就是“=”和“:=”两个的区别。
?=
如果变量 curname 前面没有被赋值,那么此变量就是“zuozhongkai”,如果前面已经赋过值了,那么就使用前面赋的值。
“+=”
Makefile 中的变量是字符串,有时候我们需要给前面已经定义好的变量添加一些字符串进去,此时就要使用到符号“+=”
常用的三种:$ @、 $ <和 $ ^,
我们直接看写好的makefile
目标…... : 依赖文件集合……
命令 1
命令 2
……
“$^”的意思是所有依赖文件的集合
arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^
相当于
arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf start.o main.o
“$@”的意思是目标集合
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
相当于
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf ledc.bin
“$<”的意思是依赖目标集合的第一个文件
%.o:%.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
相当于
start.o:start.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o start.o start.s
makefile的函数
Makefile 支持函数,类似 C 语言一样,Makefile 中的函数是已经定义好的,我们直接使用,
不支持我们自定义函数。make 所支持的函数不多,但是绝对够我们使用了,函数的用法如下:
$(函数名 参数集合)
或者
${函数名 参数集合}
可以看出,调用函数和调用普通变量一样,使用符号“
”
来
标
识
。
参
数
集
合
是
函
数
的
多
个
参
数
,
参
数
之
间
以
逗
号
“
,
”
隔
开
,
函
数
名
和
参
数
之
间
以
“
空
格
”
分
隔
开
,
函
数
的
调
用
以
“
”来标识。参数集合是函数的多个 参数,参数之间以逗号“,”隔开,函数名和参数之间以“空格”分隔开,函数的调用以“
”来标识。参数集合是函数的多个参数,参数之间以逗号“,”隔开,函数名和参数之间以“空格”分隔开,函数的调用以“”开
头
patsubst
patsubst函数
用来完成模式字符串替换
$(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”。
如:
INCDIRS := imx6ul \
bsp/clk \
bsp/led \
bsp/delay \
bsp/beep \
bsp/key \
bsp/gpio
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
给每个INCDIRS加上 -I
wildcard
- 函数 wildcard
通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时,
通配符不会自动展开,这个时候就要用到函数 wildcard,使用方法如下:
$(wildcard PATTERN…)
比如:
$(wildcard *.c)
上面的代码是用来获取当前目录下所有的.c 文件,类似“%”。
- 函数 foreach
foreach 函数用来完成循环,用法如下:
$(foreach , ,)
此函数的意思就是把参数中的单词逐一取出来放到参数 中,然后再执行所
包含的表达式。每次都会返回一个字符串,循环的过程中, 中所包含的每个字符串
会以空格隔开,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串将会是
函数 foreach 函数的返回值。
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
这里的意思先是使用foreach 找到SRCDIRS下所有的目录,然后在通过wildcard 获取当前目录下所有的.s和.c 文件
函数 notdir
看名字就是知道去除文件中的目录部分,也就是提取文件名,用法如下:
$(notdir <names…>)
此函数用与从文件名序列中提取出文件名非目录部分,比如:
$(notdir </src/a.c>)
提取文件“/src/a.c”中的非目录部分,也就是文件名“a.c”。
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
这里面提取到没有路径的.c和.s
后面我这里在调用把.和.c换成.o
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
这里就是obj/xxx.o了
VPATH
VPATH := $(SRCDIRS)
VPATH 是指定搜索目录的,这里指定的搜素目录就是变量 SRCDIRS 所保存的
目录,这样当编译的时候所需的.S 和.c 文件就会在 SRCDIRS 中指定的目录中查找。
Makefile 伪目标
用伪目标的主要是为了避免 Makefile 中定义的只执行命令的目标和工作目录下的实际文
件出现名字冲突,有时候我们需要编写一个规则用来执行一些命令,但是这个规则不是用来创
建文件的
clean:
rm *.o
rm main
上述规则中并没有创建文件 clean 的命令,因此工作目录下永远都不会存在文件 clean,当
我们输入“make clean”以后,后面的“rm *.o”和“rm main”总是会执行。可是如果我们“手
贱”,在工作目录下创建一个名为“clean”的文件,那就不一样了,当执行“make clean”的时
候,规则因为没有依赖文件,所以目标被认为是最新的,因此后面的 rm 命令也就不会执行,我
们预先设想的清理工程的功能也就无法完成。
为了避免这个问题,我们可以将 clean 声明为伪
目标,声明方式如下:
.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 $@ $<
$(COBJS) : obj/%.o : %.c
这里用到了个静态模式
$(COBJS) 意思是定义了一系列的目标文件
obj/%.o 是指明了targets的模式
%.c 是目标的依赖模式
$(COBJS) : obj/%.o : %.c 表示将所有的.c文件编译成.o文件存放在obj目录下