分类: LINUX
2010-11-07 16:53:52
一、变量的赋值:
1、=(递归展开式赋值)
特点:
左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧的变量不一定非要是已定义好的值,其也可以使用后面定义的值。
对这种变量的引用,在引用的地方是严格的文本替换过程,此变量值的字符串原模原样的出现在引用它的地方。如果此变量定义中存在对其他变量的引用,这些被引用的变量会在它被展开的同时被展开。就是说在变量定义时,变量值中对其他变量的引用不会被替换展开。而是,变量在引用它的地方进行替换展开的同时,它所引用的其他变量才会被替换展开。
例如:
foo=$(bar)
bar=test
all:$(foo)
最终是在执行到“all:$(foo)”这一步时,所有前面定义的变量才会展开。
2、 := (直接展开式赋值)
特点:
与递归展开赋值不同,直接展开式赋值时,对变量的引用必须是前面已经定义好的。
在每一步如果有对变量的引用都会被被展开,而不是到最终的引用时才被展开。
例如:
bar :=test
foo :=$(bar)
all:$(foo)
在每一步如果有对变量的引用,就会在当前步展开。
3、 ?= (条件赋值)
特点:
只有此变量在之前没有赋值的情况下,才会对变量进行赋值。否则就不会对此变量赋值。
4、 += (追加赋值)
特点:
如果变量在前面没有被定义过,则“+=”会自动变成“=”,如果变量在前面有定义过,则会继承前一次的赋值操作符。
二、变量的高级用法
1、变量的替换引用
对于一个已经定义的变量,可以使用“替换引用”将其值使用指定的字符(字符串)进行替换。格式为:$(VAR:A=B),意思是、替换变量VAR中所有“A”字符结尾的字为“B”。
2、变量的嵌套引用
一个变量名之中可以包含对其它变量的引用。这种情况我们称之为“变量的嵌套引用”
X=Y
Y=Z
A:=$($(X)
最终A的值为:Z
三、变量的修饰符
1、override指示符
防止命令行中定义变量的值替换在makefile中变量的值。
在makefile中定义变量CFLAGS=-g
当输入:make CFLAGS=-wall时,则CFLAGS的值会变为-Wall.
在makefile中定义变量override CFLAGS=-g
当输入:make CFLAGS=-wall时,则CFLAGS的值会变为-g
在makefile中定义变量override CFLAGS+=-g
当输入:make CFLAGS=-wall时,则CFLAGS的值会变为-g –Wall
2、系统环境变量
在make运行时,在所有makefile中系统环境变量都是可见的。能从上一级makefile中传递到下一级makefile中。
如果在makefile中存在对系统环境变量的定义,则会覆盖系统的环境变量。但是当mak –e 参数时,makefile中和命令行中对环境变量的定义将不会生效。
Makefile中可以通过export指定一个全局变量。
3、目标指定变量
目标指定变量只在它指定的目标中有效。
例如:
prog:prog.o foo.o bar.o
prog:CFLAGS=-g
则参数CFLAGS=-g对目标prog,以及目标所引发的:prog.o foo.o bar.o都有效。
4、模式指定变量
模式指定变量定义将一个变量值指定到符合特定模式的目标上去。
例如:
%.o:CFLAGS=-g
则参数CFLAGS=-g对所有符合%.o模式的都有效。
四、变量的类型
1、普通变量
Makefile中定义的变量
2、系统环境变量
整个系统的环境变量,对整个系统有效。
3、make环境变量
MAKEILFES:包含需要读入的makefile文件。但不能作为终极目标。
MAKEFILE_LIST:make读取的文件名
.VARIABLES:包含引用点之前的全部全局变量列表(包含空变量、make的内嵌变量),但不包含目标指定变量
.LIBPATTERNS:指定搜索库文件的类型和顺序。默认为lib%.so lib%.a
CURDIR:代表当前目录
MAKEILFES:传递命令行的参数
MAKELEVEL:代表调用的深度
MAKECMDGOALS:记录命令行参数指定的终极目标列表
CFLAGS:采用隐含规则时的编译参数
4、自动化变量
模式规则中,规则的目标和依赖文件名代表了一类文件名;规则的命令是对所有这一类文件重建过程的描述,显然,在命令中不能出现具体的文件名,否则模式规则失去意义。那么在模式规则的命令行中该如何表示文件,将是本小节的讨论的重点。
假如你需要书写一个将.c文件编译到.o文件的模式规则,那么你该如何为gcc书写正确的源文件名?当然了,不能使用任何具体的文件名,因为在每一次执行模式规则时源文件名都是不一样的。为了解决这个问题,就需要使用“自动环变量”,自动化变量的取值是根据具体所执行的规则来决定的,取决于所执行规则的目标和依赖文件名。
1、$@
表示规则的目标文件名。如果目标是一个文档文件(Linux中,一般称.a文件为文档文件,也称为静态库文件),那么它代表这个文档的文件名。在多目标模式规则中,它代表的是哪个触发规则被执行的目标文件名。
2、$%
当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。例如,规则的目标是“foo.a(bar.o)”,那么,“$%”的值就为“bar.o”,“$@”的值为“foo.a”。如果目标不是静态库文件,其值为空。
3、$<
规则的第一个依赖文件名。如果是一个目标文件使用隐含规则来重建,则它代表由隐含规则加入的第一个依赖文件。
4、$?
所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代表的是库成员(.o文件)。
5、$^
规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的只能是所有库成员(.o文件)名。一个文件可重复的出现在目标的依赖中,变量“$^”只记录它的一次引用情况。就是说变量“$^”会去掉重复的依赖文件。
6、$+
类似“$^”,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库的交叉引用场合。
7、$*
在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“%”所代表的部分(当文件名中存在目录时,“茎”也包含目录(斜杠之前)部分)。例如:文件“dir/a.foo.b”,当目标的模式为“a.%.b”时,“$*”的值为“dir/a.foo”。“茎”对于构造相关文件名非常有用。
自动化变量“$*”需要两点说明:
Ø 对于一个明确指定的规则来说不存在“茎”,这种情况下“$*”的含义发生改变。此时,如果目标文件名带有一个可识别的后缀,那么“$*”表示文件中除后缀以外的部分。例如:“foo.c”则“$*”的值为:“foo”,因为.c是一个可识别的文件后缀名。GUN make对明确规则的这种奇怪的处理行为是为了和其它版本的make兼容。通常,在除静态规则和模式规则以外,明确指定目标文件的规则中应该避免使用这个变量。
Ø 当明确指定文件名的规则中目标文件名包含不可识别的后缀时,此变量为空。
自动化变量“$?”在显式规则中也是非常有用的,使用它规则可以指定只对更新以后的依赖文件进行操作。例如,静态库文件“libN.a”,它由一些.o文件组成。这个规则实现了只将更新后的.o文件加入到库中:
lib: foo.o bar.o lose.o win.o
ar r lib $?
以上罗列的自动量变量中。其中有四个在规则中代表文件名($@、$<、$%、$*)。而其它三个的在规则中代表一个文件名列表。GUN make中,还可以通过这七个自动化变量来获取一个完整文件名中的目录部分和具体文件名部分。在这些变量中加入“D”或者“F”字符就形成了一系列变种的自动环变量。这些变量会出现在以前版本的make中,在当前版本的make中,可以使用“dir”或者“notdir”函数来实现同样的功能。
8、$(@D)
表示目标文件的目录部分(不包括斜杠)。如果“$@”是“dir/foo.o”,那么“$(@D)”的值为“dir”。如果“$@”不存在斜杠,其值就是“.”(当前目录)。注意它和函数“dir”的区别!
9、$(@F)
目标文件的完整文件名中除目录以外的部分(实际文件名)。如果“$@”为“dir/foo.o”,那么“$(@F)”只就是“foo.o”。“$(@F)”等价于函数“$(notdir $@)”。
10:
$(*D)
$(*F)
分别代表目标“茎”中的目录部分和文件名部分。
11:
$(%D)
$(%F)
当以如“archive(member)”形式静态库为目标时,分别表示库文件成员“member”名中的目录部分和文件名部分。它仅对这种形式的规则目标有效。
12:
$(
$(
分别表示规则中第一个依赖文件的目录部分和文件名部分。
13:
$(^D)
$(^F)
分别表示所有依赖文件的目录部分和文件部分(不存在同一文件)。
在讨论自动化变量时,为了和普通变量(如:“CFLAGS”)区别,我们直接使用了“$<”的形式。这种形式仅仅是为了和普通变量进行区别,没有别的目的。其实对于自动环变量和普通变量一样,代表规则第一个依赖文件名的变量名实际上是“<”,我们完全可以使用“$(<)”来替代“$<”。但是在引用自动化变量时通常的做法是“$<”,因为自动化变量本身是一个特殊字符。
GUN make同时支持“Sysv”特性,允许在规则的依赖列表中使用特殊的变量引用(一般的自动化变量只能在规则的命令行中被引用)“$$@”、“$$(@D)”和“$$(@F)”(注意:要使用“$$”),它们分别代表了“目标的完整文件名”、“目标文件名中的目录部分”和“目标的实际文件名部分”。这三个特殊的变量只能用在明确指定目标文件名的规则中或者是静态模式规则中,不用于隐含规则中。另外Sysv make和GNU make对规则依赖的处理也不尽相同。Sysv make对规则的依赖进行两次替换展开,而GUN make对依赖列表的处理只有一次,对其中的变量和函数引用直接进行展开。
自动化变量的这个古怪的特性完全是为了兼容Sysv 版本的makefile文件。在使用GNU make时可以不考虑这个,也可以在Makefile中使用伪目标“.POSIX”来禁止这一特性。
chinaunix网友2010-11-08 15:25:21
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com