变量的使用(五)

来源:互联网 发布:淘宝神笔下载 编辑:程序博客网 时间:2024/05/29 12:51

6 变量的使用

变量是makefile中为一串字符定义的名字,这个名字就是变量,这个字符串就是变量的值。变量在调用它的地方被显式替换。(有些版本的make把变量叫做宏。)

变量和函数在makefile被读取时展开,但recipe中的变量和函数会在将其传递给shell时展开。用define指令定义变量,=右边的是变量值。

变量可以是文件名列表、传给编译器的选项、需要运行的程序、源文件路径、输出的写入目录,或者你可以想象的任何东西。

变量名可以由不包含:#=或者空格的任意字符组成。然而当变量名包含字母数字下划线之外的字符时要格外小心,因为有些版本的make不能将这种变量传递给子make。以.和大写字母开始的变量拥有特殊的含义,它们留给将来新版make使用。

变量名是区分大小写的,名字fooFOO,和Foo分别指向不同的变量。

通常变量名使用大写字母,但是我们推荐makefile内部使用的变量使用小写字母,控制隐含规则或者用户用于覆盖命令行选项的变量使用大写字母。

很少有变量只有一个字母或者很少几个字母。这些一般都是自动变量,它们都有特殊用途。

6.1 变量引用基础

要替换变量的值,可以在$符号后面用括号或者花括号把变量名括起来:$(foo)或者${foo}都是对变量foo的有效引用。要在文件名或recipe中使用$字符,必须用两个$$代替。

可以在很多地方使用变量引用,诸如targets,prerequisites,recipes等大多数指令和新变量值中都可以使用变量引用。下面是常见示例,变量包含了程序中所有的object文件名:

objects = program.o foo.o utils.oprogram : $(objects)        cc -o program $(objects)$(objects) : defs.h

变量引用执行严格的文本替换。如下规则:

foo = cprog.o : prog.$(foo)        $(foo)$(foo) -$(foo) prog.$(foo)

相当于:

prog.o : prog.c        cc -c prog.c

由于变量赋值时,变量值前的空格被省略,所以foo的值就是c。(千万不要把你的makefile写成这样。)

如果$符号后面跟一个字符而不是$,并且没有被括号括起来,那么这个字符被当作变量名。因此可以使用$x引用变量x。但是并不鼓励这么做,除非是自动变量。

6.2 变量的两个特点

在GNU make中,可以用两种方法给变量赋值,称之为变量的两个特性。这两个特性根据变量定义的方式以及变量展开的时机来区分。

第一个特性是递归展开变量(recursively expanded variable)。这种变量使用=或者defile指令定义。你指定的值会被逐字符展开,如果其中包含变量引用,这些引用在这个变量被替换时展开。这叫做递归展开。例如:

foo = $(bar)bar = $(ugh)ugh = Huh?all:;echo $(foo)

会回显Huh?$(foo)被展开成$(bar),而后者展开成$(ugh),最终输出Huh?

其他版本make只支持这一种特性。它有利也有弊。一个好处是:

CFLAGS = $(include_dirs) -Oinclude_dirs = -Ifoo -Ibar

CFLAGS在一个recipe中展开时,它会展开成-Ifoo -Ibar -O。不好之处在于你不能给这个变量后面添加别的东西:

CFLAGS = $(CFLAGS) -O

这会导致变量展开时无限循环。(实际上make会检查到这个无限循环,并报错)

另一个不好的是,定义中包含的任何函数引用都会在变量每次展开时执行一次。这会拖慢make的运行速度,更糟的是,这会让通配符和shell函数给出错误的结果,因为你不能控制函数在何时被调用,以及被调用的次数。

另一个特性可以避免递归展开变量遇到的问题和不便,它就是简单展开变量(simply expanded variables)

简单展开变量使用:=::=定义。在GNU make中两者等效,然而只有::=在POSIX标准中有声明(2012年才将::=添加到POSIX标准中,因此更老的版本不支持)。

只有在简单展开变量在定义时,其中包含的变量和函数引用才会被展开一次。简单展开变量的值实际上是文本展开后的结果字符串。其中不包含任何其它变量的引用,它在定义时直接包含其它变量的值。因此:

x := fooy := $(x) barx := later

等效于:

y := foo barx := later

当一个简单展开变量被引用时,按字面值展开。

下面是更复杂的示例,展现了:=shell函数连接使用。其中使用了变量MAKELEVEL,其值在逐层下传时不断增加。

ifeq (0,${MAKELEVEL})whoami    := $(shell whoami)host-type := $(shell arch)MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}endif

使用:=的一个好处是,进入一个目录的recipe看起来像这样:

${subdirs}:        ${MAKE} -C $@ all

简单展开变量通常使复杂的makefile变得更清晰,因为其工作方式类似于大多数编程语言中的变量。它允许你用变量本身的值来定义变量自己(或者其值可以被扩展函数以某种方式处理),同时可以极大的提高扩展函数的效率。

你也可以使用它们在变量中引入前导空格。在变量引用被替换和函数调用之前,前导空格在你的输入中被抛弃。这意味着你在变量值中包含前导空格,通过变量引用保护它们,像这样:

nullstring :=space := $(nullstring) # end of the line

这里变量space的值是一个空格。注释# end of the line只是为了让语句更清晰,这行最后的那个空格是有效的(但是并不易读)。如果你要在变量值结尾加入一个空格,在空格后加上注释会让程序更清晰。同样,如果你不想在结尾加上空格,那么最好不要在语句结束后加上若干空格,然后写上注释:

dir := /foo/bar    # directory to put the frobs in

这儿变量dir的值是/foo/bar(包括四个空格),这可能并不是你想要的。(想象一下像$(dir)/file的使用)

?=是变量的另一个赋值操作符,称作条件变量赋值操作符,因为它只在变量没有被定义时生效。下面的声明:

FOO ?= bar

等效于:

ifeq ($(origin FOO), undefined)    FOO = barendif

注意,给变量设置一个空值也是变量定义,?=不会重新设置这个变量。

6.3 变量引用的高级特性

这部分讲述变量的一些高级特性,以使你可以更灵活的使用变量引用。

6.3.1 引用替换

引用替换是指用你指定的值替换变量。形如$(var:a=b)(或者${var:a=b}),表示获取变量var的值,在其中用b替换单词结尾的每一个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)相同,但是a必须包含一个%字符,其等效于$(patsubst a,b,$(var))

例如:

foo := a.o b.o c.obar := $(foo:%.o=%.c)

bar的值为a.c b.c c.c

6.3.2 计算变量名

计算变量的名字是一个复杂的概念,只在复杂的makefile中使用。大多数情况下不需要考虑它们,只需要知道变量名中包含$可能产生奇怪的结果。然而,如果你是那种想弄明白一切的人,或许你会对这部分感兴趣,那就接着往下读吧。

变量可以在变量名中被引用。这称之为计算变量名或者叫嵌套变量引用。例如:

x = yy = za := $($(x))

a定义为z:内层的$(x)展开成y,而$(y)展开成z。这儿引用变量名并没有显式声明,它通过$(x)计算。对$(x)的引用嵌套于外层的变量引用中。

前面的例子展示了两层嵌套,但是更多层的前提是可行的。例如,三层嵌套:

x = yy = zz = ua := $($($(x)))

在一个变量名中引用递归展开的变量叫做二次展开(re-expanded)。例如:

x = $(y)y = zz = Helloa := $($(x))

定义aHello$($(x))变成$($(y)),再变成$(z),最后变成Hello

嵌套变量引用也可以包含改变引用的函数调用。例如使用subst函数:

x = variable1variable2 := Helloy = $(subst 1,2,$(x))z = ya := $($($(z)))

最终定义aHello。很怀疑是否有人会像这样曲折的写一个嵌套引用,但是它是正确的:$($($(z)))展开为$($(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 := dirselsedf := filesendifdirs := $($(a1)_$(df))

将会根据use_ause_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.c1.c 2.c 3.c

对嵌套引用变量的唯一限制是,不能用于指定被调用的函数名的一部分。这是因为函数名是在嵌套引用被展开之前就已经确定下来了。例如:

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作为函数sortstrip的参数进行调用。如果有可能,这个限制会在未来去掉。

你也可以把计算变量名用于变量赋值的左边或者用于define指令,就像:

dir = foo$(dir)_sources := $(wildcard $(dir)/*.c)define $(dir)_print = lpr $($(dir)_sources)endef

这个例子定义了变量dirfoo_sources,和foo_print

注意,嵌套引用变量不同于递归展开变量,尽管两者都用于复杂的makefile程序中。

6.4 变量如何获取它们的值

变量有多种方法获取值:

  • 在运行make时用特定值覆盖变量原有值。

  • 在makefile中使用赋值语句或者逐字定义语句。

  • 环境变量成为make变量。

  • 每个规则的自动变量获得属于自己的值。每个自动变量都有单一的常规用法。

  • 有些变量有常量的初始值。

6.5 设置变量

在一个makefile中设置一个变量时,在一行中使用变量名开始,其后跟=:=,或::=。该行中剩下的部分都是变量的值。例如:

objects = main.o foo.o bar.o utils.o

定义了一个名为objects的变量。变量名前后的空格和紧跟=的空格被忽略。

=定义的变量成为递归展开(recursively expanded)变量。以:=::=定义的变量称为简单展开(simply expanded)变量,其定义中可以包含变量引用,变量引用会在定义时就展开。

变量名中可能含有函数和变量引用,当该行被读取时,会去查找其中使用的变量名。

变量值的长度没有限制,只取决于计算机内存。可以将较长的变量分割成更易读取的多行。

如果你没设置的话,大多数变量都被认为其值只包含空字符串。有些变量有内建的初始值,并不为空,但是你也可以通过普通方式来设置它们。有些特殊的变量在每条规则中会被设置成新的值,这些叫做自动变量

如果你希望一个变量在没有被设置时才能被设置,可以使用?=代替=。下面两个示例设置FOO的效果相同:

FOO ?= bar

与:

ifeq ($(origin FOO), undefined)FOO = barendif

shell的赋值运算符!=可以用来执行shell脚本,并且为它的输出设置变量。这个操作符首先计算右边的部分,然后将结果传递给shell去执行。如果执行的结果以一个信号终止,这个新行被移除。其它所有的新行以空格代替。随后结果字符串被放入递归展开变量。例如:

hash != printf '\043'file_list != find . -name '*.c'

如果执行的结果产生一个$,而你又不想把跟在它后面的东西解释为变量,那你需要把每个$替换成$$当作执行的一部分。或者,你可以为shell函数调用的程序运行的结果设置一个简单展开变量。例如:

hash := $(shell printf '\043')var := $(shell find . -name "*.c")

由于使用了shell函数,被调用的shell脚本的退出状态被存放在变量.SHELLSTATUS中。

6.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 another.o

使用+=类似于:

objects = main.o foo.o bar.o utils.oobjects := $(objects) another.o

但是其间的差异对于更复杂的变量变得很重要。

当变量之前并未定义,+=行为与=相同,其定义一个递归展开变量。但是如果前面有定义,那么+=会遵循变量原始定义的特征。

当你用+=增加一个变量的值,make的行为本质上与你在原始定义中包含这些额外的文本是一样的。如果你最开始以:=::=定义变量,使其成为简单展开变量。+=追加到简单展开变量的定义时,在将文本追加到旧值之前,先将文本展开,就像:=的行为一样。事实上:

variable := valuevariable += more

完全等效于:

variable := valuevariable := $(variable) more

另一方面,当你为一个最初使用=定义的递归展开变量使用+=时,make的做法又有一点不同。回想一下,当你定义一个递归展开变量时,make不会立马展开变量和函数引用的值。相反,make保存文本字面值,并且保存这些变量和函数的引用以便在之后当你指向新变量时展开。当为递归展开变量使用+=时,make不会展开新增的文本:

variable = valuevariable += more

基本上等效于:

temp = valuevariable = $(temp) more

当然之前要没有定义过temp才行。变量的旧值包含变量引用时这很重要,注意如下通用示例:

CFLAGS = $(inculdes) -O...CFLAGS += -pg # enable profiling

第一行用另一个变量includes的引用定义变量CFLAGS。使用=定义CFLAGS,使其成为递归展开变量,这意味着在make处理CFLAGS的定义时$(includes) -O不会展开。因此inculdes不需要在之前被定义,其只需要在CFLAGS的任何引用之前被定义即可。如果不使用+=追加CFLAGS的值,可能要这样写:

CFLAGS := $(CFLAGS) -pg # enable profiling

这很接近,但不是我们想要的。使用:=重新定义CFLAGS为简单展开变量,表示在设置这个变量之前make要展开文本$(CFLAGS) -pg。如果includes之前没有被定义,我们会得到-O -pg,并且之后再定义includes已经没有效果。相反,使用+=设置CFLAGS为未展开的$(includes) -O -pg值。因此我们保留inculdes的引用,不管在之后任何地方定义includes,引用$(CFLAGS)仍然可以使用它的值。

6.7 override指令

如果一个变量已经设置了一个命令参数,那么makefile中对该变量一般的赋值操作就会被忽略。如果你想在makefile中设置一个已经被设置命令参数的变量,可以使用override指令:

override variable = value

override variable := value

给命令行中定义的变量追加文本,可以使用:

override variable += more text

除了其它override以外,有override标志的赋值语句比其它的赋值语句有更高的优先级。之后没有被override标记的赋值或追加操作将被忽略。

voerride指令不是用来扩大makefile和命令参数之间的战争。它是用来更改或增加用户用命令参数指定的值。

例如,运行C编译器时一般都会使用-g选项,但也运行用户使用命令参数指定其它的选项。可以使用override指令:

override CFLAGS += -g

也可以将override用于define指令。下面的代码可以如期工作:

override define foo =barendef

请看下一部分关于define的介绍。

6.8 定义多行变量

另一个设置变量值的方式是使用define指令。define允许换行符出现在定义的值中,这便于定义命令序列,也方便于makefile中的eval语法。

define指令语法格式是,在define关键字之后跟变量名以及赋值操作符,变量的值出现在下面的行中,最后以新行endef结束。define定义的变量与其它变量的工作方式相同。变量名可以包含函数和变量引用,其中包含的函数和变量会在指令被读入时展开。

可以省略赋值操作符。如果省略,make假设其使用=,创建递归展开变量。当使用+=,定义的值被添加到之前的值中,新旧值用空格分开。

可以嵌套使用define指令,make会检查嵌套指令,如果没有合适的关闭指令endef,就会报错。注意以recipe前导符开始的一行被认为是recipe,因此如果defineendef前面有recipe前导符(默认tab),则不会被当作make指令。

define two-lines =echo fooecho $(bar)endef

一般的赋值操作不能包含换行符,但是define中的换行符被当作变量值的一部分(除了endef前的最后一个换行符)。

当用在recipe中时,前面的例子等效于:

two-lines = echo foo; echo $(bar)

由于两条命令以分号分开,所以其行为类似于两条分开的shell命令。而make会对两行分开的指令调用两个shell。

如果要使define定义的变量优先于命令行定义的变量,可以使用override

override define two-lines =foo$(bar)endef

6.9 未定义变量

如果想要清除一个变量,可以给它设置空值。展开这个变量会得到一个空字符串。然而,如果使用flavororigin函数,那么没有定义的变量和定义为空的变量是不同的。这种情况下可以使用undefine指令将变量取消。例如:

foo := foobar = barundefine fooundefine bar$(info $(origin foo))$(info $(flavor bar))

两个变量都会打印undefined

如果想要取消一个命令行定义的变量,可以使用override

override undefine CFLAGS

6.10 环境中的变量

make中的变量可以来自其运行的环境。每个make检测到的环境变量,都会被转换成同名等值的make变量。然而,makefile中的显式赋值,或者拥有命令参数的变量会覆盖环境变量。(如果指定-e标志,那么环境变量会覆盖makefile中的赋值操作。)

这样,通过在环境中设置CFLAGS变量,你可以让大多数makefile使用你想要的C编译选项。给变量使用有特殊意义的名字是比较安全的,因为你可以确定不会有makefile将这些名字用于其它用途。(这并不总是可靠的,有些makefile显式设置CFLAGS,这样环境中的变量值将无效。)

当make运行一条recipe,makefile中定义的变量会导入到每一个被调用的shell的环境中。这允许你为子make传递值。默认情况下,只有环境中的变量,或者命令行的变量可以递归传递。可以使用export指令传递其它变量。

不推荐在其它地方使用环境变量。将makefile的功能依赖于外部定义的环境变量是不明智的,这会导致对于相同的makefile,不同的用户会得到不同的结果。这违背了大多数makefile目的。

这个问题与变量SHELL有些类似,SHELL通常在环境中提供,用于指定交互用的shell。最好不要让这个选择影响make的行为。因此make以一种特殊的方式处理环境变量SHELL

6.11 特定目标变量值

make中的变量值通常是全局的,也就是说不管它们在哪被赋值,其效果都相同(除非它们被复位)。自动变量是一个列外。

另一个例外就是特定目标变量值(target-specific variable values)。这个特性允许你基于make当前建立的目标(target),为同一个变量定义不同的值。与自动变量一样,这些值只在当前目标的recipe(和其它特定目标变量赋值)中可用。

设置一个特定目标变量值:

target ... : variable-assignment

特定目标变量赋值可以加任意特定关键字的前缀,exportoverride,或private,这些只应用于当前变量。

多目标规则会为列表中的每个target分别创建一个特定目标值。

任何形式的赋值对variable-assignment都是有效的,递归(=),简单(:=::=),追加(+=),或者条件(?=)。所有在variable-assignment中出现的变量,只在当前目标环境中被赋值,因此任何先前定义的特定目标变量值都会受到影响。注意,这个变量与全局变量有区别:这两个变量不需要有相同的特征(递归或简单)。

特定目标变量与其它makefile变量有相同的优先级。命令行中提供的变量有更高的优先级(如果环境中指定-e选项)。override指令使特定目标变量值有更高的优先级。

特定目标变量有另外一个特性:当你定义一个特定目标变量时,其影响此目标的所有prerequisites,以及这些prerequisites的prerequisites(除非这些prerequisites用它们自己的特定目标变量值覆盖了这个变量)。因此,下面的声明:

prog : CFLAGS = -gprog : prog.o foo.o bar.o

会在prog的recipe中设置CFLAGS-g,也会在创建prog.ofoo.obar.o以及它们的prerequisites的recipe中设置CFLAGS-g

每次make调用时,一个给定的prerequisite最多只被创建一次。如果多个目标中有同一个文件作为prerequisite,并且每个目标对相同的特定目标变量有不同的值,那么第一个被创建的目标会导致这个prerequisite被创建,这个prerequisite从这个目标中继承这个特定目标值。make会忽略来自其它目标的特定目标值。

6.12 特定模板变量值

除了特定目标变量值以外,GNU make还支持特定模板变量值(pattern-specific variable values)。这种形式下,这个变量会定义在任何匹配特定模板的目标中。

设置一个特定模板变量值:

pattern ... : variable-assignment

这儿模板是%模板,与特定目标变量值一样,多模板规则为每个模板单独创建一个特定模板变量值。variable-assignment可以是任何有效的赋值操作符。任何命令行变量有更高的优先级,除非用override指定。

例如:

%.o : CFLAGS = -O

会给所有匹配模板%.o的目标设置值为-OCFLAGS

如果一个目标匹配多个模板,匹配词干最长的特定模板变量最先被使用。这表示特殊的模板比一般的模板更优先,例如:

%.o: %.c        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@lib/%.o: CFLAGS := -fPIC -g%.o: CFLAGS := -gall: foo.o lib/bar.o

这个示例中,第一个CFLAGS变量定义用于更新lib/bar.o,即使第二个模板也能匹配这个目标。如果匹配的词干长度相同,则按它们在makefile中定义的顺序考虑。

特定模板变量在目标显式定义的特定目标变量之后被查询,在父目标中定义的特定目标变量之前被查询。

6.13 抑制继承

按照前面的描述,make变量通过prerequisites被继承。这个功能允许你通过改变prerequisite的行为,来改变基于该prerequisite重建的target。例如,你可以给debug目标设置特定目标变量,然后运行make debug可以使这个变量被debug的所有的prerequisites继承,而运行make all则不会有这个变量赋值操作。

有时候你不想让一个变量被继承,make提供了private语句。尽管这个语句可用于任何变量赋值,但是在特定目标和特定模板变量中最有用。任何标记为private的变量仅对其target可见,但可以被这个目标的prerequisites继承。一个标记为private的全局变量在全局范围内可见,但是不能被任何目标继承,因此在任何recipe中都不可见。

考虑下面的例子:

EXTRA_CFLAGS =prog: private EXTRA_CFLAGS = -L/usr/local/libprog: a.o b.o

由于private语句,a.ob.o不会从目标prog中继承EXTRA_CFLAGS变量的赋值。

6.14 其它特殊变量

GNU make支持一些有特殊功能的变量。

  • MAKEFILE_LIST

    包含make处理的每个makefile文件名。当前文件在make开始处理前就加入到MAKEFILE_LIST中,因此如果一个makefile文件的第一条语句是检查这个变量的最后一个单词的话,会得到当前文件名。一旦在当前文件使用了include,那么被包含的文件会成为最后一个文件名。
    如果一个名为Makefile的makefile有如下内容:

    name1 := $(lastword $(MAKEFILE_LIST))include inc.mkname2 := $(lastword $(MAKEFILE_LIST))all:        @echo name1 = $(name1)        @echo name2 = $(name2)

    会产生如下输出:

    name1 = Makefilename2 = inc.mk
  • .DEFAULT_GOAL

    如果命令行没有指定目标,则会使用设置的默认目标。变量.DEFAULT_GOAL查看当前的默认目标,或者通过清空该值重新开始默认目标的选择算法,或者显式设置默认目标。下面的示例说明了这些情况:

    # Query the default goal.ifeq ($(.DEFAULT_GOAL),)    $(warning no default goal is set)endif.PHONY: foofoo: ; @echo $@$(warning default goal is $(.DEFAULT_GOAL))# Reset the default goal..DEFAULT_GOAL :=.PHONY: barbar: ; @echo $@$(warning default goal is $(.DEFAULT_GOAL))# Set our own..DEFAULT_GOAL := foo

    这个makefile打印如下信息:

    no default goal is setdefault goal is foodefault goal is barfoo

    注意,将超过一个的目标名赋值给.DEFAULT_GOAL是无效的,会产生一个错误。

  • MAKE_RESTARTS

    只有在这个make实例重新开始时,这个变量才会被设置。这个变量记录这个实例重新开始的次数。注意这不同于递归(变量MAKELEVEL记录)。不能设置,修改或导出这个变量。

  • MAKE_TERMOUT
    MAKE_TERMERR

    当make开始时,会检查是否有stdoutstderr将其输出显示在终端。如果有,make会分别设置MAKE_TERMOUTMAKE_TERMERR为终端设备名(或者当无法确定时设置为true)。这些变量如果被设置,则会标记为export。这些变量不能被make修改,如果已经被设置,则无法修改。
    这些值被用于决定make是否将它的输出写到终端,例如,它们可以被用于测试是否让recipe命令产生有色输出。

  • .RECIPEPREFIX

    这个变量的第一个值的第一个字符用来作为recipe行的引导字符。如果这个变量为空(默认),那这个字符是标准tab字符。例如,下面是一个有效的makefile:

    .RECIPEPREFIX = >all:> @echo Hello, world

    .RECIPEPREFIX的值可以被多次改变,一旦被设定,在下次更改之前都有效。

  • .VARIABLES

    扩展为到目前为止定义的所有全局变量名列表。它包含空值变量,以及内建变量。但不包含任何定义于特定目标环境的变量。注意,你赋给它的所有值都会被忽略,它总是返回其特定值。

  • .FEATURES

    扩展为当前版本make支持的所有特性列表。包含但不限于以下值:

    ‘archives’
    支持使用特殊文件名语法的ar文件。

    ‘check-symlink’
    支持-L--check-symlink-times)标志。

    ‘else-if’
    支持非嵌套条件else if

    ‘jobserver’
    支持job server并行建立。

    ‘oneshell’
    支持特殊目标.ONESHELL

    ‘order-only’
    支持order-only prerequisites

    ‘second-expansion’
    支持prerequisite列表二次展开。

    ‘shortest-stem’
    选择模板时,如果有多个可用选项,使用“最短词”干方法。

    ‘target-specific’
    支持特定目标和特定模板变量赋值。

    ‘undefine’
    支持undefine指令。

    ‘guile’
    使用GNU Guile作为一个嵌入式扩展语言。

    ‘load’
    支持创建用户扩展时,动态加载objects

  • .INCLUDE_DIRS

    扩展为make查找的包含makefile目录列表。

原创粉丝点击