Makefile的规则:
target ... : prerequisite...
command
...
...
target是一个目标文件,可以说object file ,也可以是执行文件,也可是标签
prerequisite使生成target所需要的文件或者是目标
command也就是make需要执行的命令
Makefile的书写命令:
每条规则中的命令和操作系统shell的命令行是一致的。
每条命令的开头必须以[Tab]开头,除非命令是紧跟在以来规则后面。
1.显示命令
@字符在命令行前面的时候,这个命令将不被make显示出来
如果带入make参数“-n”或“--just-print”,那么只是显示命令,但不会执行命令
make参数“-s”或者“--slient”则是全面禁止命令的显示
2.执行命令
当规则的目标需要被更新时,make会一条一条执行其后面的命令。
如果需要让上一条命令的结果应用在下一条命令时,应该将两条命令写在同一行
并且用分号隔开。
3.命令出错
每当命令运行完之后,make会检测每个命令的返回码,如果命令返回成功,则会继续执行
下一条命令,当规则中所有的命令成功返回后,这个规则就是成功完成。
忽略一些非错误性出错可以在Makefile的命令行前面加一个“-”号(在Tab键之后),标记为
不管命令是否出错,均认为成功。
4.嵌套执行make
大工程中,在每个功能目录里面下一个Makefile。最终由一个总控Makefile来进行控制。
总控makefile书写格式:
subsystem:
cd subdir && $(MAKE)
等价于
subsystem:
$(MAKE) -C subdir
传递变量到下级Makefile中的声明:
export <variable ...>
不想让某些变量传递到下级Makefile中,声明:
unexport <variable ...>
示例一:
export variable = value
其等价于:
variable = value
export variable
其等价于:
export variable := value
其等价于:
variable := value
export variable
如果需要传递所有变量,那么只要一个export就可以。注意:SHELL MAKEFLAGS总传递到下层
make命令中有几个参数并不往下传递
-c, -f, -h, -o, -W
5.定义命令包
如果Makefile中出现一些相同命令序列。语法:
define run-yacc
yacc $(firstword $^) #运行Yacc程序
mv y.tab.c $@ #将这个文件改名字
endef
其中,run-yacc 为命令包,不能与Makefile中的变量重名。
示例:
foo.c : foo.yacc
$(run-yacc)
在具体示例中,命令包中$^就是foo.y $@就是foo.c
变量的使用:
变量的命名可以包含字符、数字、下划线,但能含有 “:”“#”“=”或者空字符
变量区分大小写,建议使用大小写搭配的变量名
一、变量基础
变量在声明时需要给予初值,在使用的时候需要在变量名前面加上“$”,如果需要使用真实的$,那么写作$$
二、变量中的变量
1. 利用“=”。在“=”左侧是变量,右侧是变量的值。右侧变量的值可以定义在文件的任何一处。
注意:这种方法有可能会让make陷入无限的变量展开过程中去。
2. 利用“:=”操作符
例如:
x:=foo
y:=$(x)bar
x:=later
等价于:
y:=foo bar
x:=later
这种方法,前面的变量不能够使用后面的变量,只能使用前面已经定义好了的变量。
3. 如果我们需要定义一个变量值为一个空格,可以如下定义:
nullstring :=
space := $(nullstring)#end of the line
利用“#”注释符来标识变量定义的终止
4. “?=”操作符
FOO ?= bar #如果FOO没有被定义过,那么变量FOO的值就是bar,如果FOO先前定义过,那么跳过
三、变量高级用法
1.变量值的替换
替换变量中共有的部分 $(var:a=b) 或者 ${var:a=b} #把变量var中所有以“a”字串结尾的“a”替换位“b”
2.把变量的值再当成变量
简单例子
x = y
y = z
a := $($(x))
推导出: $(a)的值为z
复杂例子
x = variable1
variable2 := Hello
y = $(subst 1, 2, $(x)) #将variable1的1替换成2, y = variable2
z = y
a := $($($(z))) #$($(y)) -> $(variable2) -> Hello
四、追加变量
利用“+=”操作符来给变量追加值,如:
objects = main.o
objects += another.o # $(objects)的值即 “main.o another.o”
如果变量之前没有定义过,那么"+="自动转化为"="
如果前面有变量定义,那么"+="会继承于前次操作的赋值符
五、override指示符
六、多行变量
使用define关键字设置的值可以有换行,这有利于定义一系列的命令
七、环境变量
八、目标变量
以上所有的变量定义都是“全局变量”,在整个文件中,都可以访问。“自动化变量”除外。
如“$<”等这种变量的自动化变量就属于“规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义。
可以为某个目标设置局部变量,这种变量称为“Target-specific Variable”,可以和全局变量同名,作用范围只在这条
规则以及连带规则中。
语法:
<target ...>:<variable-assignment>
<target ...>:override<variable-assignment>
使用条件判断
语法:
<conditional-directive> #条件关键字 ifeq(<arg1>,<agr2>) 或者 ifneq(<arg1>,<arg2>) 或者 ifdef<variable-name>或者ifndef(<arg1>,<arg2>)
<text-if-true>
else
<text-if-false>
endif
函数的调用语法
函数的调用以"$"来标识,语法如下:
$(<function> <arguments>)或者${<function> <arguments>}
#function是函数名,arguments是参数,参数间用“,”分隔,函数名与参数之间以“空格”分隔。
字符串处理函数
$(subst <from>, <to>, <text>)
名称:字符串替换函数----subst
功能:把字串<text>中的<from>字符串替换成<to>
返回:函数返回被替换过后的字符串
$(patsubst <pattern>,<replacement>,<text>)
名称:模式字符串替换函数---patsubst
功能:查找<text>中的单词是否符合模式<pattern>,如果匹配,则以<replacement>替换
这里,<pattern>可以包括通配符%,表示任意长度的字串。
返回:函数返回被替换过后的字符串
$(strip <string>) 去掉空格
$(finding <find>,<in>) 查找字符串函数
$(fileter <pattern...>,<text>) 过滤函数,保留符合 模式pattern 的单词
$(fukter-out <pattern...>,<text>) 反过滤,去除符合 模式pattern的单词
$(sort <list>) 排序,默认升序
$(word <n>,<text>) 取单词函数
$(wordlist <s>,<e>,<text>) 取单词串函数
$(words <text>) 单词个数统计函数
$(furstword <text>) 首个单词函数
文件名操作函数
$(dir <names...>) 取目录函数
$(notdir <names...>) 取文件函数
$(suffix <names...>) 取后缀函数
$(basename <names...>) 取前缀函数
$(addsuffix <suffix> <names...>) 加后缀函数
$(addprefix <prefix>,<names...>) 加前缀函数
$(join <list1>,<list2>) 连接函数
隐含规则:
编译C程序的隐含规则
“<n>.o”的目标依赖目标会自动推导为“<n>.c”,并且其生成命令是 $(CC) -c $(CPPFLAGS) $(CFLAGS)
链接object文件的隐含规则
“<n>”目标依赖于“<n>.o”,通过运行C的编译器来运行链接程序生成,其生成命令是 $(CC) $(LDFLAGS) <n>.o $(LOADLIBES) $(LDLIBS)
注意:这个规则对于只有一个源文件的工程有效,同时也对多个object文件的有效
隐含规则使用的变量
C语言编译程序。默认命令是 “CC”,如果把变量“$(CC)”重定义为“gcc”,“$(CFLAGS)”重定义为“-g”,那么隐含规则中
的命令全部都会以“gcc -c -g $(CPPFLAGS)”来执行