收藏 分享(赏)

makefile变量.doc

上传人:yjrm16270 文档编号:7864304 上传时间:2019-05-28 格式:DOC 页数:20 大小:71KB
下载 相关 举报
makefile变量.doc_第1页
第1页 / 共20页
makefile变量.doc_第2页
第2页 / 共20页
makefile变量.doc_第3页
第3页 / 共20页
makefile变量.doc_第4页
第4页 / 共20页
makefile变量.doc_第5页
第5页 / 共20页
点击查看更多>>
资源描述

1、6 使用变量变量是在 makefile 中定义的名字,其用来代替一个文本字符串,该文本字符串称为该变量的值。在具体要求下,这些值可以代替目标、依赖、命令以及 makefile 文件中其它部分。(在其它版本的 make 中,变量称为宏(macros)。)在 makefile 文件读入时,除规则中的 shell 命令、使用=定义的= 右边的变量、以及使用define 指令定义的变量体此时不扩展外,makefile 文件其它各个部分的变量和函数都将扩展。变量可以代替文件列表、传递给编译器的选项、要执行的程序、查找源文件的目录、输出写入的目录,或您可以想象的任何文本。变量名是不包括:,#,=、前导或结

2、尾空格的任何字符串。然而变量名包含字母、数字以及下划线以外的其它字符的情况应尽量避免,因为它们可能在将来被赋予特别的含义,而且对于一些 shell 它们也不能通过环境传递给子 make(参阅 与子 make 通讯的变量 )。变量名是大小写敏感的,例如变量名foo, FOO, 和 Foo代表不同的变量。使用大写字母作为变量名是以前的习惯,但我们推荐在 makefile 内部使用小写字母作为变量名,预留大写字母作为控制隐含规则参数或用户重载命令选项参数的变量名。参阅 变量重载 。一少部分的变量使用一个标点符号或几个字符作为变量名,这些变量是自动变量,它们又特定的用途。参阅 自动变量 。6.1 变量

3、引用基础写一个美元符号后跟用圆括号或大括号括住变量名则可引用变量的值:$(foo) 和 $foo都是对变量foo的有效引用。$的这种特殊作用是您在命令或文件名中必须写$才有单个$的效果的原因。变量的引用可以用在上下文的任何地方:目标、依赖、命令、绝大多数指令以及新变量的值等等。这里有一个常见的例子,在程序中,变量保存着所有 OBJ 文件的文件名:objects = program.o foo.o utils.oprogram : $(objects)cc -o program $(objects)$(objects) : defs.h变量的引用按照严格的文本替换进行,这样该规则foo = cp

4、rog.o : prog.$(foo)$(foo)$(foo) -$(foo) prog.$(foo)可以用于编译 C 语言源程序prog.c。因为在变量分配时,变量值前面的空格被忽略,所以变量 foo 的值是C 。(不要在您的 makefile 文件这样写!)美元符号后面跟一个字符但不是美元符号、圆括号、大括号,则该字符将被处理为单字符的变量名。因此可以使用$x 引用变量 x。然而,这除了在使用自动变量的情况下,在其它实际工作中应该完全避免。参阅 自动变量 。6.2 变量的两个特色在 GNU make 中可以使用两种方式为变量赋值,我们将这两种方式称为变量的两个特色(two flavors)

5、。两个特色的区别在于它们的定义方式和扩展时的方式不同。变量的第一个特色是递归调用扩展型变量。这种类型的变量定义方式:在命令行中使用=定义(参阅 设置变量 )或使用 define 指令定义(参阅 定义多行变量 )。变量替换对于您所指定的值是逐字进行替换的;如果它包含对其它变量的引用,这些引用在该变量替换时(或在扩展为其它字符串的过程中)才被扩展。这种扩展方式称为递归调用型扩展。例如:foo = $(bar)bar = $(ugh)ugh = Huh?all:;echo $(foo)将回显Huh? :$(foo)扩展为$(bar),进一步扩展为$(ugh),最终扩展为Huh?。这种特色的变量是其它

6、版本 make 支持的变量类型,有缺点也有优点。大多数人认为的该类型的变量的优点是:CFLAGS = $(include_dirs) -Oinclude_dirs = -Ifoo -Ibar即能够完成希望它完成的任务:当CFLAGS在命令中扩展时,它将最终扩展为 -Ifoo -Ibar。其最大的缺点是不能在变量后追加内容,如在:CFLAGS = $(CFLAGS) -O在变量扩展过程中可能导致无穷循环(实际上 make 侦测到无穷循环就会产生错误信息)。它的另一个缺点是在定义中引用的任何函数时(参阅 文本转换函数 )变量一旦展开函数就会立即执行。这可导致 make 运行变慢,性能变坏;并且导致

7、通配符与 shell 函数(因不能控制何时调用或调用多少次)产生不可预测的结果。为避免该问题和递归调用扩展型变量的不方便性,出现了另一个特色变量:简单扩展型变量。简单扩展型变量在命令行中用:= 定义(参阅 设置变量 )。简单扩展型变量的值是一次扫描永远使用,对于引用的其它变量和函数在定义的时候就已经展开。简单扩展型变量的值实际就是您写的文本扩展的结果。因此它不包含任何对其它变量的引用;在该变量定义时就包含了它们的值。所以:x := fooy := $(x) barx := later等同于: y := foo barx := later引用一个简单扩展型变量时,它的值也是逐字替换的。这里有一个

8、稍复杂的例子,说明了:=和 shell 函数连接用法(参阅 函数 shell)。该例子也表明了变量 MAKELEVEL 的用法,该变量在层与层之间传递时值发生变化。(参阅 与子 make 通讯的变量 ,可获得变量MAKELEVEL 关于的信息。)ifeq (0,$MAKELEVEL)cur-dir := $(shell pwd)whoami := $(shell whoami)host-type := $(shell arch)MAKE := $MAKE host-type=$host-type whoami=$whoamiendif按照这种方法使用:=的优点是看起来象下述的典型的 下降到目录

9、 的命令:$subdirs:$MAKE cur-dir=$cur-dir/$ -C $ all简单扩展型变量因为在绝大多数程序设计语言中可以象变量一样工作,因此它能够使复杂的makefile 程序更具有预测性。它们允许您使用它自己的值重新定义(或它的值可以被一个扩展函数以某些方式处理),它们还允许您使用更有效的扩展函数(参阅 文本转换函数 )。您可以使用简单扩展型变量将控制的前导空格引入到变量的值中。前导空格字符一般在变量引用和函数调用时被丢弃。简单扩展型变量的这个特点意味着您可以在一个变量的值中包含前导空格,并在变量引用时保护它们。象这样:nullstring :=space := $(nu

10、llstring) # end of the line这里变量 space 的值就是一个空格,注释# end of the line包括在这里为了让人更易理解。因为尾部的空格不能从变量值中分离出去,仅在结尾留一个空格也有同样的效果(但是此时相当难读),如果您在变量值后留一个空格,象这样在行的结尾写上注释清楚表明您的打算是很不错的主意。相反,如果您在变量值后不要空格,您千万记住不要在行的后面留下几个空格再随意放入注释。例如:dir := /foo/bar # directory to put the frobs in这里变量 dir 的值是 /foo/bar (四个尾部空格),这不是预期的结果。

11、(假设/foo/bar是预期的值)。另一个给变量赋值的操作符是?=,它称为条件变量赋值操作符,因为它仅仅在变量还没有定义的情况下有效。这声明:FOO ?= bar和下面的语句严格等同(参阅 函数 origin)ifeq ($(origin FOO), undefined)FOO = barendif注意,一个变量即使是空值,它仍然已被定义,所以使用?=定义无效。6.3 变量引用高级技术本节内容介绍变量引用的高级技术。6.3.1 替换引用替换引用是用您指定的变量替换一个变量的值。它的形式$(var:a=b)(或$var:a=b),它的含义是把变量 var 的值中的每一个字结尾的 a 用 b 替换

12、。我们说在一个字的结尾 ,我们的意思是 a 一定在一个字的结尾出现,且 a 的后面要么是空格要么是该变量值的结束,这时的 a 被替换,值中其它地方的 a 不被替换。例如:foo := a.o b.o c.obar := $(foo:.o=.c)将变量bar的值设为a.c b.c c.c。参阅 变量设置 。替换引用实际是使用扩展函数 patsubst 的简写形式(参阅 字符串替换和分析函数 )。我们提供替换引用也是使扩展函数 patsubst 与 make 的其它实现手段兼容的措施。另一种替换引用是使用强大的扩展函数 patsubst。它的形式和上述的$(var:a=b)一样,不同在于它必须包含

13、单个%字符,其实这种形式等同于$(patsubst a,b,$(var)。有关于函数 patsubst 扩展的描述参阅 字符串替换和分析函数 。例如:foo := a.o b.o c.obar := $(foo:%.o=%.c)社值变量bar的值为a.c b.c c.c。6.3.2 嵌套变量引用(计算的变量名)嵌套变量引用(计算的变量名)是一个复杂的概念,仅仅在十分复杂的makefile 程序中使用。绝大多数情况您不必考虑它们,仅仅知道创建名字中含有美元标志的变量可能有奇特的结果就足够了。然而,如果您是要把一切搞明白的人或您实在对它们如何工作有兴趣,请认真阅读以下内容。变量可以在它的名字中引用

14、其它变量,这称为嵌套变量引用(计算的变量名)。例如:x = yy = za := $($(x)定义阿 a 为z:$(x)在$($(x)中扩展为y,因此$($(x)扩展为$(y),最终扩展为z。这里对引用的变量名的陈述不太明确;它根据$(x)的扩展进行计算,所以引用$(x)是嵌套在外层变量引用中的。前一个例子表明了两层嵌套,但是任何层次数目的嵌套都是允许的,例如,这里有一个三层嵌套的例子:x = yy = zz = ua := $($($(x)这里最里面的$(x) 扩展为y,因此$($(x)扩展为$(y),$(y) 扩展为z,最终扩展为u。在一个变量名中引用递归调用扩展型变量,则按通常的风格再扩

15、展。例如:x = $(y)y = zz = Helloa := $($(x)定义的 a 是Hello:$($(x)扩展为$($(y),$($(y)变为$(z), $(z)最终扩展为Hello。嵌套变量引用和其它引用一样也可以包含修改引用和函数调用(参阅 文本转换函数 )。例如,使用函数 subst(参阅 字符串替换和分析函数 ):x = variable1variable2 := Helloy = $(subst 1,2,$(x)z = ya := $($($(z)定义的 a 是Hello。任何人也不会写象这样令人费解的嵌套引用程序,但它确实可以工作:$($($(z) 扩展为$($(y),$(

16、$(y)变为$(subst 1,2,$(x)。它从变量x得到值variable1,变换替换为variable2,所以整个字符串变为$( variable2),一个简单的变量引用,它的值为Hello。嵌套变量引用不都是简单的变量引用,它可以包含好几个变量引用,同样也可包含一些固定文本。例如,a_dirs := dira dirb1_dirs := dir1 dir2a_files := filea fileb1_files := file1 file2ifeq “$(use_a)“ “yes“a1 := aelsea1 := 1endififeq “$(use_dirs)“ “yes“df :=

17、 dirselsedf := filesendifdirs := $($(a1)_$(df)根据设置的 use_a 和 use_dirs 的输入可以将 dirs 这个相同的值分别赋给a_dirs, 1_dirs, a_files 或 1_files。嵌套变量引用也可以用于替换引用:a_objects := a.o b.o c.o1_objects := 1.o 2.o 3.osources := $($(a1)_objects:.o=.c)根据 a1 的值,定义的 sources 可以是a.c b.c c.c 或 1.c 2.c 3.c。使用嵌套变量引用唯一的限制是它们不能只部分指定要调用的函

18、数名,这是因为用于识别函数名的测试在嵌套变量引用扩展之前完成。例如:ifdef do_sortfunc := sortelsefunc := stripendifbar := a d b g q cfoo := $($(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

19、 $(dir)/*.c)define $(dir)_printlpr $($(dir)_sources)endef该例子定义了变量dir,foo_sources, 和foo_print。注意:虽然嵌套变量引用和递归调用扩展型变量都是用在复杂的 makefile 文件中,但二者不同(参阅 变量的两个特色 )。6.4 变量取值变量有以下几种方式取得它们的值:l 您可以在运行 make 时为变量指定一个重载值。参阅 变量重载 。l 您可以在 makefile 文件中指定值,即变量赋值(参阅 设置变量 )或使用逐字定义变量(参阅 定义多行变量 )。l 把环境变量变为 make 的变量。参阅 环境变量

20、。l 自动变量可根据规则提供值,它们都有简单的习惯用法,参阅 自动变量 。l 变量可以用常量初始化。参阅 隐含规则使用的变量 。6.5 设置变量在 makefile 文件中设置变量,编写以变量名开始后跟=或:=的一行即可。任何跟在=或:=后面的内容就变为变量的值。例如:objects = main.o foo.o bar.o utils.o定义一个名为 objects 的变量,变量名前后的空格和紧跟=的空格将被忽略。使用=定义的变量是递归调用扩展型变量;以:=定义的变量是简单扩展型变量。简单扩展型变量定义可以包含变量引用,而且变量引用在定义的同时就被立即扩展。参阅 变量的两种特色 。变量名中也

21、可以包含变量引用和函数调用,它们在该行读入时扩展,这样可以计算出能够实际使用的变量名。变量值的长度没有限制,但受限于计算机中的实际交换空间。当定义一个长变量时,在合适的地方插入反斜杠,把变量值分为多个文本行是不错的选择。这不影响 make 的功能,但可使 makefile 文件更加易读。绝大多数变量如果您不为它设置值,空字符串将自动作为它的初值。虽然一些变量有内建的非空的初始化值,但您可随时按照通常的方式为它们赋值(参阅隐含规则使用的变量 。)另外一些变量可根据规则自动设定新值,它们被称为自动变量。参阅 自动变量 。如果您喜欢仅对没有定义过的变量赋给值,您可以使用速记符?=代替=。下面两种设置

22、变量的方式完全等同(参阅 函数 origin):FOO ?= bar和ifeq ($(origin FOO), undefined)FOO = barendif6.6 为变量值追加文本为已经定以过的变量的值追加更多的文本一般比较有用。您可以在独立行中使用+=来实现上述设想。如:objects += another.o这为变量 objects 的值添加了文本another.o(其前面有一个前导空格)。这样:objects = main.o foo.o bar.o utils.oobjects += another.o变量 objects 设置为main.o foo.o bar.o utils.o

23、 another.o。使用 += 相同于: objects = main.o foo.o bar.o utils.oobjects := $(objects) another.o对于使用复杂的变量值,不同方法的差别非常重要。如变量在以前没有定义过,则+=的作用和=相同:它定义一个递归调用型变量。然而如果在以前有定义,+=的作用依赖于您原始定义的变量的特色,详细内容参阅 变量的两种特色 。当您使用+=为变量值附加文本时,make 的作用就好象您在初始定义变量时就包含了您要追加的文本。如果开始您使用:=定义一个简单扩展型变量,再用+=对该简单扩展型变量值追加文本,则该变量按新的文本值扩展,好像在原

24、始定义时就将追加文本定义上一样,详细内容参阅 设置变量 。实际上,variable := valuevariable += more等同于:variable := valuevariable := $(variable) more另一方面,当您把+=和首次使用无符号=定义的递归调用型变量一起使用时,make 的运行方式会有所差异。在您引用递归调用型变量时,make 并不立即在变量引用和函数调用时扩展您设定的值;而是将它逐字储存起来,将变量引用和函数调用也储存起来,以备以后扩展。当您对于一个递归调用型变量使用+=时,相当于对一个不扩展的文本追加新文本。variable = valuevariab

25、le += more粗略等同于:temp = valuevariable = $(temp) more当然,您从没有定义过叫做 temp 的变量,如您在原始定义变量时,变量值中就包含变量引用,此时可以更为深刻地体现使用不同方式定义的的重要性。拿下面常见的例子,CFLAGS = $(includes) -O.CFLAGS += -pg # enable profiling第一行定义了变量 CFLAGS,而且变量 CFLAGS 引用了其它变量,includes。(变量 CFLAGS 用于 C 编译器的规则,参阅 隐含规则目录 。)由于定义时使用=,所以变量 CFLAGS 是递归调用型变量,意味着$

26、(includes) -O在 make 处理变量 CFLAGS 定义时是不扩展的;也就是变量 includes 在生效之前不必定义,它仅需要在任何引用变量 CFLAGS 之前定义即可。如果我们试图不使用+=为变量 CFLAGS 追加文本,我们可能按下述方式:CFLAGS := $(CFLAGS) -pg # enable profiling这似乎很好,但结果绝不是我们所希望的。使用:=重新定义变量 CFLAGS 为简单扩展型变量,意味着 make 在设置变量 CFLAGS 之前扩展了$(CFLAGS) -pg。如果变量 includes 此时没有定义,我们将得到-0 -pg,并且以后对变量 i

27、ncludes 的定义也不会有效。相反,使用+= 设置变量 CFLAGS 我们得到没有扩展的$(CFLAGS) 0 -pg,这样保留了对变量 includes 的引用,在后面一个地方如果变量 includes 得到定义,$(CFLAGS)仍然可以使用它的值。6.7 override 指令如果一个变量设置时使用了命令参数(参阅 变量重载 ),那么在 makefile 文件中通常的对该变量赋值不会生效。此时对该变量进行设置,您需要使用override 指令,其格式如下:override variable = value或override variable := value为该变量追加更多的文本,使

28、用:override variable += more text参阅 为变量值追加文本 。override 指令不是打算扩大 makefile 和命令参数冲突,而是希望用它您可以改变和追加哪些设置时使用了命令参数的变量的值。例如,假设您在运行 C 编译器时总是使用-g开关,但您允许用户像往常一样使用命令参数指定其它开关,您就可以使用 override 指令:override CFLAGS += -g您也可以在 define 指令中使用 override 指令,下面的例子也许就是您想要得: override define foobarendef关于 define 指令的信息参阅下节。6.8 定义

29、多行变量设置变量值的另一种方法时使用 define 指令。这个指令有一个特殊的用法,既可以定义包含多行字符的变量。这使得定义命令的固定次序十分方便(参阅 定义固定次序命令 )。在 define 指令同一行的后面一般是变量名,当然,也可以什么也没有。变量的值由下面的几行给出,值的结束由仅仅包含 endef 的一行标示出。除了上述在语法上的不同之外,define 指令象=一样工作:它创建了一个递归调用型变量(参阅 变量的两个特色 )。变量的名字可以包括函数调用和变量引用,它们在指令读入时扩展,以便能够计算出实际的变量名。define two-linesecho fooecho $(bar)ende

30、f变量的值在通常的赋值语句中只能在一行中完成,但在 define 指令中在define 指令行以后 endef 行之前中间所有的行都是变量值的一部分(最后一行除外,因为标示 endef 那一行不能认为是变量值的一部分)。前面的例子功能上等同于:two-lines = echo foo; echo $(bar)因为两命令之间用分号隔开,其行为很接近于两个分离的 shell 命令。然而,注意使用两个分离的行,意味着 make 请求 shell 两次,每一行都在独立的子shell 中运行。参阅 执行命令 。如果您希望使用 define 指令的变量定义比使用命令行定义的变量优先,您可以把 define

31、 指令和 override 指令一块使用:override define two-linesfoo$(bar)endef参阅 override 指令 。6.9 环境变量make 使用的变量可以来自 make 的运行环境。任何 make 能够看见的环境变量,在 make 开始运行时都转变为同名同值的 make 变量。但是,在 makefile 文件中对变量的具体赋值,或使用带有参数的命令,都可以对环境变量进行重载(如果明确使用-e标志,环境变量的值可以对 makefile 文件中的赋值进行重载,参阅 选项概要 ,但是这在实际中不推荐使用。)这样,通过在环境中设置变量 CFLAGS,您可以实现在绝

32、大多数 makefile 文件中的所有 C 源程序的编译使用您选择的开关。因为您知道没有 makefile 将该变量用于其它任务,所以这种使用标准简洁含义的变量是安全的(但这也是不可靠的,一些 makefile 文件可能设置变量 CFLAGS,从而使环境中变量 CFLAGS 的值失效)。当使用递归调用的 make 时,在外层 make 环境中定义的变量,可以传递给内层的 make(参阅 递归调用 make)。缺省方式下,只有环境变量或在命令行中定义的变量才能传递给内层 make。您可以使用 export 指令传递其它变量,参阅 与子 make 通讯的变量 。环境变量的其它使用方式都不推荐使用。

33、将 makefile 的运行完全依靠环境变量的设置、超出 makefile 文件的控制范围,这种做法是不明智的,因为不同的用户运行同一个 makefile 文件有可能得出不同的结果。这和大部分 makefile 文件的意图相违背。变量 SHELL 在环境中存在,用来指定用户对交互的 shell 的选择,因此使用变量 SHELL 也存字类似的问题。这种根据选定值影响 make 运行的方式是很不受欢迎的。所以,make 将忽略环境中变量 SHELL 的值(在 MS-DOS 和 MS-Windows中运行例外,但此时变量 SHELL 通常不设置值,参阅 执行命令 )。6.10 特定目标变量的值mak

34、e 中变量的值一般是全局性的;既,无论它们在任何地方使用,它们的值是一样的(当然,您重新设置除外);自动变量是一个例外(参阅 自动变量 )。另一个例外是特定目标变量的值,这个特点允许您可以根据 make 建造目标的变化改变变量的定义。象自动变量一样,这些值只能在一个目标的命令脚本的上下文起作用。可以象这样设置特定目标变量的值:target . : variable-assignment或这样:target . : override variable-assignmenttarget .中可含有多个目标,如此,则设置的特定目标变量的值可在目标列表中的任一个目标中使用。variable-assig

35、nment使用任何赋值方式都是有效的:递归调用型(=)、静态(:=)、追加(+=)或条件(?=)。所有出现在variable-assignment中的变量能够在特定目标target .的上下文中使用:也就是任何以前为特定目标 target .定义的特定目标变量的值在这些特定目标中都是有效的。注意这种变量值和全局变量值相比是局部的值:这两种类型的变量不必有相同的类型(递归调用 vs.静态)。特定目标变量的值和其它 makefile 变量具有相同的优先权。一般在命令行中定义的变量(和强制使用-e情况下的环境变量)的值占据优先的地位,而使用 override 指令定义的特定目标变量的值则占据优先地位

36、。特定目标变量的值有另外一个特点:当您定义一个特定目标变量时,该变量的值对特定目标 target .的所有依赖有效,除非这些依赖用它们自己的特定目标变量的值将该变量重载。例如:prog : CFLAGS = -gprog : prog.o foo.o bar.o将在目标 prog 的命令脚本中设置变量 CFLAGS 的值为-g,同时在创建prog.o, foo.o, 和 bar.o的命令脚本中变量 CFLAGS 的值也是-g,以及 prog.o,foo.o, 和bar.o的依赖的创建命令脚本中变量 CFLAGS 的值也是-g。6.11 特定格式变量的值除了特定目标变量的值(参阅上小节)外,GN

37、U make 也支持特定格式变量的值。使用特定格式变量的值,可以为匹配指定格式的目标定义变量。在为目标定义特定目标变量后将搜寻按特定格式定义的变量,在为该目标的父目标定义的特定目标变量前也要搜寻按特定格式定义的变量。设置特定格式变量格式如下:pattern . : variable-assignment或这样:pattern . : override variable-assignment这里的pattern是%-格式。象特定目标变量的值一样,pattern .中可含有多个格式,如此,则设置的特定格式变量的值可在匹配列表中的任一个格式中的目标中使用。variable-assignment使用任何赋值方式都是有效的,在命令行中定义的变量的值占据优先的地位,而使用 override 指令定义的特定格式变量的值则占据优先地位。例如:%.o : CFLAGS = -O搜寻所有匹配格式%.o 的目标,并将它的变量 CFLAGS 的值设置为-0。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报