18.追加变量值:“+=”
objects = main.o foo.o bar.o utils.o
objects += another.o
于是,我们的$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o被追加进去了,使用“+=”操作符,可以模拟为下面的这种例子:
objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o
所不同的是,用“+=”更为简洁。
如果变量之前没有定义过,那么,“+=”会自动变成“=”.如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符.
19.override 指示符(暂时没有用到,所以也没有理解)
如果有变量是通常 make 的命令行参数设置的,那么 Makefile 中对这个变量的赋值会被忽略。
如果你想在 Makefile 中设置这类参数的值,那么,你可以使用“override”指示符。其语
法是:
override
=
override :=
20.环境变量(与19结合看,大概还是能懂)
make 运行时的系统环境变量可以在 make 开始运行时被载入到 Makefile 文件中,但是如果 Makefile 中已定义了这个变量,或是这个变量由 make 命令行带入,那么系统的环境变量的值将被覆盖。(如果 make 指定了“-e”参数,那么,系统环境变量将覆盖 Makefile 中定义的变量)
因此,如果我们在环境变量中设置了“CFLAGS”环境变量, 那么我们就可以在所有的Makefile 中使用这个变量了。这对于我们使用统一的编译参数有比较大的好处。如果Makefile 中定义了 CFLAGS,那么则会使用Makefile 中的这个变量,如果没有定义则使用系统环境变量的值,一个共性和个性的统一,很像“全局变量”和“局部变量”的特性。
21.目标变量(认真看一遍自然就懂了)
前面我们所讲的在 Makefile 中定义的变量都是“全局变量”,在整个文件,我们都可以访问这些变量。当然,
“自动化变量”除外,如“$<”等这种类量的自动化变量就属于“规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义。当然,我样同样可以为某个目标设置局部变量,这种变量被称为“TargetspecificVariable”,它可以和“全局变量”同名,因为它的作用范围只在这条规则以及连带规则中,
所以其值也只在作用范围内有效。而不会影响规则链以外的全局变量的值。
其语法是:
:
: overide
可以是前面讲过的各种赋值表达式,如“=”、“:=”、“+=”或是“?=”。第二个语法是针对于 make 命令行带入的变量,或是系统环境变量。这个特性非常的有用,当我们设置了这样一个变量,
这个变量会作用到由这个目标所引发的所有的规则中去。如:
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o : prog.c
$(CC) $(CFLAGS) prog.c
foo.o : foo.c
$(CC) $(CFLAGS) foo.c
bar.o : bar.c
$(CC) $(CFLAGS) bar.c
在这个示例中,不管全局的$(CFLAGS)的值是什么,在 prog 目标,以及其所引发的所有规则中(prog.o foo.o bar.o 的规则),$(CFLAGS)的值都是“-g”.
22.模式变量(结合21来学习)
eg:%.o : CFLAGS = -O
同样,模式变量的语法和“目标变量”一样:
:
: override
override 同样是针对于系统环境传入的变量,或是 make 命令行指定的变量。
23.条件判断
(1)ifeq
ifeq (A,B)
命令动作1
else
命令动作2
endif
功能:如果A=B,执行动作1,如果不等,执行动作2。
(2)ifneq
(3)ifdef
注意,ifdef 只是测试一个变量是否有值,其并不会把变量扩展到当前位置。还是来看两个例子:
示例一:
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
示例二:
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
第一个例子中,“$(frobozz)”值是“yes”,第二个则是“no”。
(4)ifndef
下面的收获是函数方面的,嘿嘿
1.语法
函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
$( )
或是
${ }
例:
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
在这个示例中,
$(comma)的值是一个逗号。
$(space)使用了$(empty)定义了一个空格,
$(foo) 的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值是“a,b,c”。
2.字符串处理函数(较多,具体参考韦书或者这本)
$(subst ,,) 字符串替换
$(patsubst ,,) 格式替换
$(strip ) 去空格
$(findstring ,) 查找字符串
$(filter ,) 过滤函数
$(filter-out ,) 结果与上面一个互补
$(sort ) 排序
$(word ,) 取第n个单词
$(wordlist ,,) 取第s到e个单词
$(words ) 单词个数统计
$(firstword ) 取第一个单词
3.文件名操作函数
$(dir ) 取路径
$(notdir ) 取文件名
$(suffix ) 取后缀
$(basename ) 取路径+文件名
$(addsuffix ,) 添加后缀
$(addprefix ,) 添加前缀
$(join ,) 连接函数
eg:$(join aaa bbb , 111 222 333)返回值是“aaa111 bbb222 333”。
$(wildscard pattern) 查找某格式文件
4.foreach 函数(就像for循环)
$(foreach ,,)
举个例子:
names := a b c d
files := $(foreach n,$(names),$(n).o)
上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为 foreach 函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
5.if 函数
$(if ,)
6.call 函数(就像当于函数调用,还可以带入参数)
$(call ,,,...)
当 make 执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参数,,依次取代。而的返回值就是 call 函数的返回值。例如:
reverse = $(1) $(2)
foo = $(call reverse,a,b)
那么,foo 的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,
如:
reverse = $(2) $(1)
foo = $(call reverse,a,b)
此时的 foo 的值就是“b a”。
7.origin 函数(运用有点难度,还是在运用中去掌握吧)
origin 函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:
$(origin )
8.shell 函数(简单,易懂)
eg:
contents := $(shell cat foo)
files := $(shell echo *.c)
9.控制 make 的函数
error和waring函数,暂时了解。
下面讲讲make运行的收获
1.常见伪目标
“all”
这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
“clean”
这个伪目标功能是删除所有被 make 创建的文件。
“install”
这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
“print”
这个伪目标的功能是例出改变过的源文件。
“tar”
这个伪目标功能是把源程序打包备份。也就是一个 tar 文件。
“dist”
这个伪目标功能是创建一个压缩文件,一般是把 tar 文件压成 Z 文件。或是 gz 文件。
“TAGS”
这个伪目标功能是更新所有的目标,以备完整地重编译使用。
“check”和“test”
这两个伪目标一般用来测试 makefile 的流程。
2.检查规则
“-n” 不执行参数,这些参数只是打印命令
“-t” 把目标文件的时间更新,但不更改目标文件。也就是说,make 假装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。
“-q” 找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,当然也不会执行编译,如果目标不存在,其会打印出一条出错信息。(我怎么觉得这个用处不大呢)
3.make 的参数(太多了,具体用到的时候再去看吧)
下面讲讲隐含规则的收获
1.编译 C 程序的隐含规则
“.o”的目标的依赖目标会自动推导为“.c”,并且其生成命令是
“$(CC) –c $(CPPFLAGS) $(CFLAGS)”
2.汇编和汇编预处理的隐含规则
“.o” 的目标的依赖目标会自动推导为“.s”,默认使用编译品“as”,并且其 生 成 命 令 是 : “$(AS) $(ASFLAGS)” 。 “.s” 的 目 标 的 依 赖 目 标 会 自 动 推 导 为“.S”,默认使用 C 预编译器“cpp”,并且其生成命令是:“$(AS) $(ASFLAGS)”。
3.链接 Object 文件的隐含规则
“”目标依赖于“.o”,通过运行 C 的编译器来运行链接程序生成(一般是“ld”),其生成命令是:“$(CC) $(LDFLAGS) .o $(LOADLIBES) $(LDLIBS)”。这个规则对于只有一个源文件的工程有效,同时也对多个 Object 文件(由不同的源文件生成)的也有效。
如果没有一个源文件和你的目标名字(相关联,那么,你最好写出自己的生成规则,不然,隐含规则会报错的。
4.隐含规则使用的变量(仅仅列出了自认为对自己有用的一些)
(1)关于命令的变量
AS
汇编语言编译程序。默认命令是“as”。
CC
C 语言编译程序。默认命令是“cc”。
RM
删除文件命令。默认命令是“rm –f”。
(2)关于命令参数的变量
下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是空。
ASFLAGS
汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。
CFLAGS
C 语言编译器参数。
5.隐含规则链(理解,遇到的时候再说)
6.自动化变量
$@ 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$< 依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$? 所有比目标新的依赖目标的集合。以空格分隔。
$^ 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+ 这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。(其实感觉这个用处不大)
$* 这个变量表示目标模式中"%"及其之前的部分。(如果目标是"dir/a.foo.b",并且目标的模是"a.%.b",那么,"$*"的值就是"dir /a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的后缀是 make 所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是 make 所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是 GNU make 的,跟我一起写 Makefile很有可能不兼容于其它版本的 make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是 make 所不能识别的,那么"$*"就是空值。)
$% 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows 下是[.lib]),那么,其值为空。(这个我感觉用处也不大)
在上述所列出来的自动量变量中。四个变量($@、$<、$%、$*)在扩展时只会有一个文件,而另三个的值是一个文件列表。
对于上面的七个变量分别加上"D"(目录)或是"F"(文件)的含义:(举个例子就可以了)
eg:
$(@D)表示"$@"的目录部分(不以斜杠作为结尾),如果"$@"值是"dir/foo.o",那么"$(@D)"就是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。$(@F)表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir $@)"。
最后想提醒一下的是,对于"$<",为了避免产生不必要的麻烦,我们最好给$后面的那个特定字符都加上圆括号,比如,"$(<)"就要比"$<"要好一些。
差不多了,后面的有些总结了现在也没有啥用,用到的时候再去翻也不迟,嘿嘿。
阅读(1737) | 评论(0) | 转发(1) |