y := foo bar x := later 引用一个简单扩展型变量时,它的值也是逐字替换的。这里有一个稍复杂的例子,说明了‘:=’和shell函数连接用法(参阅函数shell)。该例子也表明了变量MAKELEVEL的用法,该变量在层与层之间传递时值发生变化。(参阅与子make通讯的变量,可获得变量MAKELEVEL关于的信息。)
nullstring := space := $(nullstring) # end of the line 这里变量space的值就是一个空格,注释‘# end of the line’包括在这里为了让人更易理解。因为尾部的空格不能从变量值中分离出去,仅在结尾留一个空格也有同样的效果(但是此时相当难读),如果您在变量值后留一个空格,象这样在行的结尾写上注释清楚表明您的打算是很不错的主意。相反,如果您在变量值后不要空格,您千万记住不要在行的后面留下几个空格再随意放入注释。例如:
dir := /foo/bar # directory to put the frobs in 这里变量dir的值是‘/foo/bar ’(四个尾部空格),这不是预期的结果。(假设‘/foo/bar’是预期的值)。
6.3.2嵌套变量引用(计算的变量名) 嵌套变量引用(计算的变量名)是一个复杂的概念,仅仅在十分复杂的makefile程序中使用。绝大多数情况您不必考虑它们,仅仅知道创建名字中含有美元标志的变量可能有奇特的结果就足够了。然而,如果您是要把一切搞明白的人或您实在对它们如何工作有兴趣,请认真阅读以下内容。 变量可以在它的名字中引用其它变量,这称为嵌套变量引用(计算的变量名)。例如: x = y y = z a := $($(x)) 定义阿a为‘z’:‘$(x)’在‘$($(x))’中扩展为‘y’,因此‘$($(x))’扩展为‘$(y)’,最终扩展为‘z’。这里对引用的变量名的陈述不太明确;它根据‘$(x)’的扩展进行计算,所以引用‘$(x)’是嵌套在外层变量引用中的。 前一个例子表明了两层嵌套,但是任何层次数目的嵌套都是允许的,例如,这里有一个三层嵌套的例子: x = y y = z z = u a := $($($(x))) 这里最里面的‘$(x)’ 扩展为‘y’,因此‘$($(x))’扩展为‘$(y)’,‘$(y)’ 扩展为‘z’,最终扩展为‘u’。 在一个变量名中引用递归调用扩展型变量,则按通常的风格再扩展。例如: x = $(y) y = z z = Hello a := $($(x)) 定义的a是‘Hello’:‘$($(x))’扩展为‘$($(y))’,‘$($(y))’变为‘$(z)’, $(z)’最终扩展为‘Hello’。 嵌套变量引用和其它引用一样也可以包含修改引用和函数调用(参阅文本转换函数)。例如,使用函数subst(参阅字符串替换和分析函数): x = variable1 variable2 := Hello y = $(subst 1,2,$(x)) z = y a := $($($(z))) 定义的a是‘Hello’。任何人也不会写象这样令人费解的嵌套引用程序,但它确实可以工作:‘$($($(z)))’ 扩展为‘$($(y))’,‘$($(y))’变为‘$(subst 1,2,$(x))’。它从变量‘x’得到值‘variable1’,变换替换为‘variable2’,所以整个字符串变为‘$( variable2)’,一个简单的变量引用,它的值为‘Hello’。 嵌套变量引用不都是简单的变量引用,它可以包含好几个变量引用,同样也可包含一些固定文本。例如, a_dirs := dira dirb 1_dirs := dir1 dir2
foo := $($(func) $(bar)) 则给变量‘foo’的值赋为‘sort a d b g q c' 或 ‘strip a d b g q c',而不是将‘a d b g q c’作为函数sort或strip的参数。如果在将来去掉这种限制是一个不错的主意。 您也可以变量赋值的左边使用嵌套变量引用,或在define指令中。如: dir = foo $(dir)_sources := $(wildcard $(dir)/*.c) define $(dir)_print lpr $($(dir)_sources) endef 该例子定义了变量‘dir',‘foo_sources', 和‘foo_print'。 注意:虽然嵌套变量引用和递归调用扩展型变量都是用在复杂的makefile文件中,但二者不同(参阅变量的两个特色)。 6.4变量取值 变量有以下几种方式取得它们的值: l 您可以在运行make时为变量指定一个重载值。参阅变量重载。 l 您可以在makefile文件中指定值,即变量赋值(参阅设置变量)或使用逐字定义变量(参阅定义多行变量)。 l 把环境变量变为make的变量。参阅环境变量。 l 自动变量可根据规则提供值,它们都有简单的习惯用法,参阅自动变量。 l 变量可以用常量初始化。参阅隐含规则使用的变量。 6.5设置变量 在makefile文件中设置变量,编写以变量名开始后跟‘=’或‘:=’的一行即可。任何跟在‘=’或‘:=’后面的内容就变为变量的值。例如: objects = main.o foo.o bar.o utils.o 定义一个名为objects的变量,变量名前后的空格和紧跟‘=’的空格将被忽略。 使用‘=’定义的变量是递归调用扩展型变量;以‘:=’定义的变量是简单扩展型变量。简单扩展型变量定义可以包含变量引用,而且变量引用在定义的同时就被立即扩展。参阅变量的两种特色。 变量名中也可以包含变量引用和函数调用,它们在该行读入时扩展,这样可以计算出能够实际使用的变量名。 变量值的长度没有限制,但受限于计算机中的实际交换空间。当定义一个长变量时,在合适的地方插入反斜杠,把变量值分为多个文本行是不错的选择。这不影响make的功能,但可使makefile文件更加易读。 绝大多数变量如果您不为它设置值,空字符串将自动作为它的初值。虽然一些变量有内建的非空的初始化值,但您可随时按照通常的方式为它们赋值(参阅隐含规则使用的变量。)另外一些变量可根据规则自动设定新值,它们被称为自动变量。参阅自动变量。 如果您喜欢仅对没有定义过的变量赋给值,您可以使用速记符‘?=’代替‘=’。下面两种设置变量的方式完全等同(参阅函数origin): FOO ?= bar 和
objects = main.o foo.o bar.o utils.o objects := $(objects) another.o 对于使用复杂的变量值,不同方法的差别非常重要。如变量在以前没有定义过,则‘+=’的作用和‘=’相同:它定义一个递归调用型变量。然而如果在以前有定义,‘+=’的作用依赖于您原始定义的变量的特色,详细内容参阅变量的两种特色。 当您使用‘+=’为变量值附加文本时,make的作用就好象您在初始定义变量时就包含了您要追加的文本。如果开始您使用‘:=’定义一个简单扩展型变量,再用‘+=’对该简单扩展型变量值追加文本,则该变量按新的文本值扩展,好像在原始定义时就将追加文本定义上一样,详细内容参阅设置变量。实际上, variable := value variable += more 等同于:
variable := value variable := $(variable) more 另一方面,当您把‘+=’和首次使用无符号‘=’定义的递归调用型变量一起使用时,make的运行方式会有所差异。在您引用递归调用型变量时,make并不立即在变量引用和函数调用时扩展您设定的值;而是将它逐字储存起来,将变量引用和函数调用也储存起来,以备以后扩展。当您对于一个递归调用型变量使用‘+=’时,相当于对一个不扩展的文本追加新文本。 variable = value variable += more 粗略等同于: