Makefile 语法学习
① 为什么需要 Makefile
高效地编译程序
修改源文件或头文件,只需要重新编译牵涉到的文件,就可以重新生成 APP
②Makefile语法
一个简单的 Makefile 文件包含一系列的“规则”,其样式如下:
目标(target)…: 依赖(prerequiries)…
命令(command)
`
如果“依赖文件”比“目标文件”更加新,那么执行“命令”来重新生成“目标文件”。
命令被执行的 2 个条件:依赖文件比目标文件新,或是 目标文件还没生成。
先介绍 Makefile 的 2 个函数:
A. $(foreach var,list,text)
简单地说,就是 for each var in list, change it to text。 对 list 中的每一个元素,取出来赋给 var,然后把 var 改为 text 所描述的形式。
B. $(wildcard pattern)
pattern 所列出的文件是否存在,把存在的文件都列出来。
objs := main.o sub.o
test : $(objs)
gcc -o test $^
#需要判定是否存在依赖文件
#.main.o.d .sub.o.d
dep_files := $(foreach f,$(objs),.$(f).d)
dep_files := $(wildcard $(dep_files))
#把依赖的文件包含起来
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : $.c
gcc -Wp,-MD,.$@.d -c -o $@ $^
clean:
rm *.o test -f
distclean:
rm $(dep_files) *.o test -f
知识点
A. make 命令的使用:
执行 make 命令时,它会去当前目录下查找名为“Makefile”的文件,并根据它的指示去执行操作,生成第一个目标。
我们可以使用“-f”选项指定文件,不再使用名为“Makefile”的文件,比如:
make -f Makefile.build
我们可以使用“-C”选项指定目录,切换到其他目录里去,比如:
make -C a/ -f Makefile.build
B. 即时变量、延时变量:
A = xxx // 延时变量
B ?= xxx // 延时变量,只有第一次定义时赋值才成功;如果曾定义过,此赋值无效
C := xxx // 立即变量
D += yyy // 如果 D 在前面是延时变量,那么现在它还是延时变量;
// 如果 D 在前面是立即变量,那么现在它还是立即变量
例如:
A = $@
test:
@echo $A
变量 A 是延时变量,它的值在使用时才展开、才确定。
上述 Makefile 中,变量 A 的值在执行时才确定,它等于 test,是延时变量。
如果使用“A := @ ” , 这 是 立 即 变 量 , 这 时 @”,这是立即变量,这时 @”,这是立即变量,这时@为空,所以 A 的值就是空
C. 变量的导出(export):
D. Makefile 中可以使用 shell 命令:
比如:
TOPDIR := $(shell pwd)
E. 在 Makefile 中怎么放置第 1 个目标:
执行 make 命令时如果不指定目标,那么它默认是去生成第 1 个目标。
所以“第 1 个目标”,位置很重要。有时候不太方便把第 1 个目标完整地放在文件前面,这时可以在文
件的前面直接放置目标,在后面再完善它的依赖与命令。比如:
First_target: // 这句话放在前面
F. 假想目标:
我们的 Makefile 中有这样的目标:
clean:
rm -f $(shell find -name “*.o”)
rm -f $(TARGET)
如果当前目录下恰好有名为“clean”的文件,那么执行“make clean”时它就不会执行那些删除命令。
这时我们需要把“clean”这个目标,设置为“假想目标”,这样可以确保执行“make clean”时那些删
除命令肯定可以得到执行。
使用下面的语句把“clean”设置为假想目标:
.PHONY : clean
G. 常用的函数:
i. $(foreach var,list,text)
简单地说,就是 for each var in list, change it to text。 对 list 中的每一个元素,取出来赋给 var,然后把 var 改为 text 所描述的形式。
例子:
objs := a.o b.o
dep_files := $(foreach f,
(
o
b
j
s
)
,
.
(objs), .
(objs),.(f).d) // 最终 dep_files := .a.o.d .b.o.d
ii. $(wildcard pattern)
pattern 所列出的文件是否存在,把存在的文件都列出来。
例子:
src_files := $( wildcard *.c) // 最终 src_files 中列出了当前目录下的所有.c 文件
iii. $(filter pattern…,text)
把 text 中符合 pattern 格式的内容,filter(过滤)出来、留下来。
例子:
obj-y := a.o b.o c/ d/
DIR := $(filter %/, $(obj-y)) //结果为:c/ d/
iv. $(filter-out pattern…,text)
把 text 中符合 pattern 格式的内容,filter-out(过滤)出来、扔掉。
例子:
obj-y := a.o b.o c/ d/
DIR := $(filter-out %/, $(obj-y)) //结果为:a.o b.o
vi. $(patsubst pattern,replacement,text)
寻找text’中符合格式
pattern’的字,用replacement’替换它们。
pattern’和`replacement’
中可以使用通配符。
比如:
subdir-y := c/ d/
subdir-y := $(patsubst %/, %, $(subdir-y)) // 结果为:c d
H
$@ 表示目标文件
$^ 表示所有的依赖文件
$< 表示第一个依赖文件
$? 表示比目标还要新的依赖文件列表