一、Make总体认识:
0)Makefile的所有内容包括五个话题,选项,规则,条件,变量,函数,其中最为重要的又是规则,其他都是为规则进行服务的。Makefle要干的所有事情就是怎样写好一个规则。
1)Make的作用其实非常的简单,包括两个:一是决定哪些工程文件需要重新编译,另一个是驱动编译系统进行编译,最后连接所有文件生成最终目标(可执行文件)
2)Make可以实现编译器支持的所有语言工程的编译工作,Make除可以用来代码工程外,还可以用来实现任何其他的动态实时更新(一个文件更新了,其他文件是否要更新)
3)Makefile的语法其实极其的简单就下面这么一条:如果prerequisites中的任何一个文件比targets中的文件新的话则执行下面的command,这个东西叫作Makefile的规则rules
4)书写自己工程的Makefile的时候,记住要遵守约定成熟的一些写法,可以参考任何开源代码中Makefile的书写风格
5)Make的执行过程其实也包括两个阶段:第一阶段也可以叫为预处理,第二个阶段才是执行。在预处理阶段包括:读取Makefile文件,内建所有的变量,变量函数展开,建立目标于依赖关系链表等
第二阶段根据第一阶段已经建立的依赖结构关系链表来决定那些关系需要更新,并使用相应的规则来重建目标。(通过描述数据库来分析执行)
二、选项:
make [-选项][宏定义][目标]
常用通用选项:
1)make -f makefile文件名
2)make -C subdir 到subdir下面去执行make, 通过export来传递变量到下一级make
3)make -k 当遇到错误时不停止,而是继续向下执行
4)make target 执行指定目标,而不是默认的目标(第一次出现的target)
5)make -w 显示进入/离开目录过程,make -C会自动打开
6)make -e 系统环境中的变量会覆盖Makefile定义的变量
7)make -B 认为所有的目标都需要更新,相当于make clean;make
8)make -j 指定可同时执行的命令数目
9)make -r 取消make支持的所有的隐含规则
10)make -I 指定被包含makefile文件的搜索目录
常用调试选项:
1)make -n 只输出,不执行,调试用
2)make -d 打印所有的调试信息,等价于:make --debug=a
3)make -b 输出基本调试信息,包括哪些目标过期了
4)make -v 输出更为详细的信息,包括:解析的makefile文件名,不需要重建文件等
5)make -i 输出所有使用到的隐含规则描述
6)make -qp 打印出make读取的Makefile的所有数据(包括规则和变量的值)
7)make –p -f /dev/null” 查看make执行前的预设规则和变量
三、规则:
1)规则的语法:
targets,targets,...: [prerequisites,,..]
command
.......
target:叫作目标,可以是目标文件,可执行文件,还可以是一个表示动作的标签lable(伪目标phony targets.)
prerequisites: 叫作依赖,即要生成targets所需要的文件,或者目标
command:通过执行以下命令来生成上面的目标
需要注意的是:
*当make没有带任何目标参数时,make执行的是默认目标的规则,否则执行指定的目标的规则
*在执行一个规则前,需要检测依赖中的每一个文件的规则,也即是说依赖中的每一个文件可能也是一个目 标(也包括一个依赖),所以规则的执行是递归执行的。
*command前必须有tab
*需要强制执行的操作可以没有prerequisites,比如:make clean
*Makefile中用"#"进行注释
*有些目标是约定成俗的,比如:clean;install;all;check;test;tar;print等
2)伪目标Phony Targets:
在phony target前面加上.PHONY来修饰,这样就会忽略名称叫clean的文件,rm前带个-号则会忽略后面的动作出现错误,而继续向下执行
.PHONY : clean
clean :
-rm edit $(objects)
3)隐含规则:
*编译C程序时的隐含规则
“xyz.o”的目标的依赖目标会自动推导为“xyz.c”,并且其生成命令是“$(CC) –c $(CPPFLAGS) $(CFLAGS)”
*编译C++程序时的隐含规则
“xyz.o”的目标的依赖目标会自动推导为“xyz.cc”或是“xyz.C”,并且其生成命令是“$(CXX) –c $(CPPFLAGS) $(CFLAGS)”
*汇编和汇编预处理的隐含规则
“xyz.o” 的目标的依赖目标会自动推导为“xyz.s”,默认使用编译器“as”,并且其生成命令是:“$(AS) $(ASFLAGS)”。
“xyz.s” 的目标的依赖目标会自动推导为“xyz.S”,默认使用C预编译器“cpp”,并且其生成命令是:“$(AS) $(ASFLAGS)”。
*链接*.o文件的隐含规则
“xyz”目标依赖于“xyz.o”,通过运行C 的编译器来运行链接程序生成(一般是“ld”),其生成命令是:“$(CC) $(LDFLAGS) xyz.o $(LOADLIBES) $(LDLIBS)”
注意:常见的隐含规则有十个,其中包括其他语言和yacc/lex的隐含规则,这里只列出编译C/C++最常用的隐含规则
隐含规则中所使用的变量:
动作变量:$(AR), $(AS), $(CC), $(CXX), $(CPP), $(RM)
参数变量:$(ARFLAGS), $(ASFLAGS), $(CFLAGS), $(CXXFLAGS), $(CPPFLAGS), $(LDFLAGS) #默认情况都为空
*注意:这些变量可以通过环境变量,输入参数,自定义变量进行覆盖
4)模式规则:
*和普通规则不同的是规则的目标及依赖中可以有模式字符"%", “%.o : %.c”,它表示:所有的.o文件依赖于对应的.c文件
*可以使用模式规则来定义隐含规则
*模式字符“%”的匹配和替换发生在规则中所有变量和函数引用展开之后,变量和函数的展开一般发生在make读取Makefile时
自动化变量:
所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。
这种自动化变量只应出现在规则的命令中,非常常用。
$@:表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合
$^:规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的只能是所有库成员(.o文件)名。
一个文件可重复的出现在目标的依赖中,变量“$^”只记录它的一次引用情况。就是说变量“$^”会去掉重复的依赖文件。
$%:当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。例如,规则的目标是“foo.a(bar.o)”,那么,“$%”的值就为“bar.o”,“$@”的值为“foo.a”。如果目标不是静态库文件,其值为空
$<:规则的第一个依赖文件名。如果是一个目标文件使用隐含规则来重建,则它代表由隐含规则加入的第一个依赖文件。
$?;所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代表的是库成员(.o文件)。
$(@D):表示目标文件的目录部分(不包括斜杠)。
$$(@F):目标文件的完整文件名中除目录以外的部分(实际文件名)。
等等,
当然关于规则还有很多其他的内容,比如:后缀规则,缺省规则等,但用的较少,则略过
四、变量:
变量的定义:
1)variable = value value . . .
2)variable:= value
variable1 += variable2
变量引用:
$(variable)
${variable}
变量替换:
$(var:a=b) #表示变量var中的所有以a结尾的单词都替换为以b结尾
bar := $(foo:%.o=%.c) #这个是静态模式的替换,替换的语义即是把所有.o结尾的单词改为.c结尾
变量重置:
override variable = value
override variable := value
这样定义的变量可以覆盖由make通过参数传入的变量初始值,或者环境变量
目标变量:
: [override] variable = value
prog : CFLAGS = -g
此种变量在目标及目标引发的所有规则中有效
模式变量:
:[[override]] variable = value
%.o : variable = value
可以把变量定义在符合这种模式的所有目标上
命令包变量:
define cmds_name
command1
command2
....
endif
环境变量:
MAKELEVEL #记录make嵌套执行的层数
VPATH #一般搜索路径
.LIBPATTERNS #
五、条件:
ifeq/ifneq (
, )
else
#endif
ifdef/ifndef #测试变量是否有值
else
#endif
六、函数:
函数调用语法:
$(fun_name argument,,)
Make的内嵌函数列表:
文本处理函数
$(subst FROM,TO,TEXT) #把字串中的字符串替换成
$(patsubst PATTERN,REPLACEMENT,TEXT) #搜索“TEXT”中以空格分开的单词,将符合模式“PATTERN”替换为“REPLACEMENT”
$(strip STRINT) #去掉字串“STRINT”开头和结尾的空字符,并将其中多个连续空字符合并为一个空字符
$(findstring FIND,IN) #如果在“IN”之中存在“FIND”,则返回“FIND”,否则返回空
$(filter PATTERN…,TEXT) #过滤掉字串“TEXT”中所有不符合模式“PATTERN”的单词,保留所有符合此模式的单词
$(filter-out PATTERN...,TEXT) #过滤掉字串“TEXT”中所有符合模式“PATTERN”的单词,保留所有不符合此模式的单词
$(sort LIST) #给字串“LIST”中的单词以首字母为准进行排序(升序),并去掉重复的单词
$(word N,TEXT) #取字串“TEXT”中第“N”个单词(“N”的值从1开始)
$(wordlist S,E,TEXT) #从字串“TEXT”中取出从“S”开始到“E”的单词串
$(words TEXT) #计算字串“TEXT”中单词的数目
$(firstword NAMES…) #取字串“NAMES…”中的第一个单词
文件名处理函数
$(dir NAMES…) #从文件名序列“Name1 Name2 …”中取出各个文件名的目录部分
$(notdir NAMES…) #从文件名序列“NAMES…”中取出非目录部分
$(suffix NAMES…) #从文件名序列“NAMES…”中取出各个文件名的后缀
$(basename NAMES…) #从文件名序列“NAMES…”中取出各个文件名的前缀部分
$(addsuffix SUFFIX,NAMES…) #为“NAMES…”中的每一个文件名添加后缀“SUFFIX”
$(addprefix PREFIX,NAMES…) #为“NAMES…”中的每一个文件名添加前缀“PREFIX”
$(join LIST1,LIST2) #将字串“LIST1”和字串“LIST2”各单词进行对应连接
$(wildcard PATTERN) #列出当前目录下所有符合模式“PATTERN”格式的文件名
foreach 函数
$(foreach VAR,LIST,TEXT) #它是一个循环函数。类似于Linux的shell中的for语句
if 函数
$(if CONDITION,THEN-PART[,ELSE-PART]) #函数“if”提供了一个在函数上下文中实现条件判断的功能。就像make所支持的条件语句—ifeq一样
call函数
$(call VARIABLE,PARAM,PARAM,...) #是唯一一个可以创建定制化参数函数的引用函数。使用这个函数可以实现对用户自己定义函数引用
value函数
$(value VARIABLE) #提供了一种在不对变量进行展开的情况下获取变量值的方法
eval函数
$(eval PARAM,...) #根据其参数的关系、结构,对它们进行替换展开。
origin函数
$(origin VARIABLE) #函数“origin”查询参数“VARIABLE”(一个变量名)的出处
shell函数
$(shell cat foo) #所实现的功能和shell中的引用(``)相同
make的控制函数
$(error TEXT…) #产生致命错误,并提示“TEXT…”信息给用户,并退出make的执行
$(warning TEXT…) #它不会导致致命错误(make不退出),而只是提示“TEXT…”,make的执行过程继续
参考地址:
《GNU Make v3.8中文手册》
七、其他补充
1)如果一个目录下只有一个文件main.c,则make main则会由main.c生成可执行文件main
2)在要执行的命令前加"@",则这条命令不进行回显
3)写在不同行的命令会在不同的shell下面进行执行的,如果写在同一行则会串行执行
4)在上一行更改了环境变量,并不会影响到下一行命令中。如果要影响,则需要写到同一行上去。
阅读(1590) | 评论(0) | 转发(0) |