定义阿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
a_files := filea fileb
1_files := file1 file2
ifeq "$(use_a)" "yes"
a1 := a
else
a1 := 1
endif
ifeq "$(use_dirs)"
"yes"
df := dirs
else
df := files
endif
dirs := $($(a1)_$(df))
根据设置的use_a和use_dirs的输入可以将dirs这个相同的值分别赋给a_dirs, 1_dirs, a_files 或 1_files。
嵌套变量引用也可以用于替换引用:
a_objects := a.o b.o c.o
1_objects := 1.o 2.o 3.o
sources := $($(a1)_objects:.o=.c)
根据a1的值,定义的sources可以是`a.c b.c c.c' 或 `1.c 2.c 3.c'。
使用嵌套变量引用唯一的限制是它们不能只部分指定要调用的函数名,这是因为用于识别函数名的测试在嵌套变量引用扩展之前完成。例如:
ifdef do_sort
func := sort
else
func := strip
endif
bar := a d b g q c
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
l
您可以在运行make时为变量指定一个重载值。参阅变量重载。
l
l
您可以在makefile文件中指定值,即变量赋值(参阅设置变量)或使用逐字定义变量(参阅定义多行变量)。
l
l
把环境变量变为make的变量。参阅环境变量。
l
l
自动变量可根据规则提供值,它们都有简单的习惯用法,参阅自动变量。
l
l
变量可以用常量初始化。参阅隐含规则使用的变量。
6.5设置变量
在makefile文件中设置变量,编写以变量名开始后跟‘=’或‘:=’的一行即可。任何跟在‘=’或‘:=’后面的内容就变为变量的值。例如:
objects = main.o foo.o bar.o utils.o
定义一个名为objects的变量,变量名前后的空格和紧跟‘=’的空格将被忽略。
使用‘=’定义的变量是递归调用扩展型变量;以‘:=’定义的变量是简单扩展型变量。简单扩展型变量定义可以包含变量引用,而且变量引用在定义的同时就被立即扩展。参阅变量的两种特色。
变量名中也可以包含变量引用和函数调用,它们在该行读入时扩展,这样可以计算出能够实际使用的变量名。
变量值的长度没有限制,但受限于计算机中的实际交换空间。当定义一个长变量时,在合适的地方插入反斜杠,把变量值分为多个文本行是不错的选择。这不影响make的功能,但可使makefile文件更加易读。
绝大多数变量如果您不为它设置值,空字符串将自动作为它的初值。虽然一些变量有内建的非空的初始化值,但您可随时按照通常的方式为它们赋值(参阅隐含规则使用的变量。)另外一些变量可根据规则自动设定新值,它们被称为自动变量。参阅自动变量。
如果您喜欢仅对没有定义过的变量赋给值,您可以使用速记符‘?=’代替‘=’。下面两种设置变量的方式完全等同(参阅函数origin):
FOO ?= bar
和
ifeq ($(origin FOO), undefined)
FOO = bar
endif
6.6 为变量值追加文本
为已经定以过的变量的值追加更多的文本一般比较有用。您可以在独立行中使用‘+=’来实现上述设想。如:
objects += another.o
这为变量objects的值添加了文本‘another.o’(其前面有一个前导空格)。这样:
objects = main.o foo.o bar.o utils.o
objects += another.o
变量objects 设置为‘main.o foo.o bar.o utils.o
another.o'。
使用 `+=' 相同于:
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
粗略等同于:
temp = value
variable = $(temp) more
当然,您从没有定义过叫做temp的变量,如您在原始定义变量时,变量值中就包含变量引用,此时可以更为深刻地体现使用不同方式定义的的重要性。拿下面常见的例子,
CFLAGS = $(includes) -O
...
CFLAGS += -pg # enable profiling
第一行定义了变量CFLAGS,而且变量CFLAGS引用了其它变量,includes。(变量CFLAGS用于C编译器的规则,参阅隐含规则目录。)由于定义时使用‘=’,所以变量CFLAGS是递归调用型变量,意味着‘$(includes)
-O’在make处理变量CFLAGS定义时是不扩展的;也就是变量includes在生效之前不必定义,它仅需要在任何引用变量CFLAGS之前定义即可。如果我们试图不使用‘+=’为变量CFLAGS追加文本,我们可能按下述方式:
CFLAGS := $(CFLAGS) -pg # enable profiling
这似乎很好,但结果绝不是我们所希望的。使用‘:=’重新定义变量CFLAGS为简单扩展型变量,意味着make在设置变量CFLAGS之前扩展了‘$(CFLAGS) -pg’。如果变量includes此时没有定义,我们将得到‘-0 -pg’,并且以后对变量includes的定义也不会有效。相反,使用‘+=’ 设置变量CFLAGS我们得到没有扩展的‘$(CFLAGS) –0 -pg’,这样保留了对变量includes的引用,在后面一个地方如果变量includes得到定义,‘$(CFLAGS)’仍然可以使用它的值。
6.7 override指令
如果一个变量设置时使用了命令参数(参阅变量重载),那么在makefile文件中通常的对该变量赋值不会生效。此时对该变量进行设置,您需要使用override指令,其格式如下:
override variable = value
或
override variable := value
为该变量追加更多的文本,使用:
override variable += more text
参阅为变量值追加文本。
override指令不是打算扩大makefile和命令参数冲突,而是希望用它您可以改变和追加哪些设置时使用了命令参数的变量的值。
例如,假设您在运行C编译器时总是使用‘-g’开关,但您允许用户像往常一样使用命令参数指定其它开关,您就可以使用override指令:
override CFLAGS += -g
您也可以在define指令中使用override指令,下面的例子也许就是您想要得:
override define foo
bar
endef
关于define指令的信息参阅下节。
6.8定义多行变量
设置变量值的另一种方法时使用define指令。这个指令有一个特殊的用法,既可以定义包含多行字符的变量。这使得定义命令的固定次序十分方便(参阅定义固定次序命令)。
在define指令同一行的后面一般是变量名,当然,也可以什么也没有。变量的值由下面的几行给出,值的结束由仅仅包含endef的一行标示出。除了上述在语法上的不同之外,define指令象‘=’一样工作:它创建了一个递归调用型变量(参阅变量的两个特色)。变量的名字可以包括函数调用和变量引用,它们在指令读入时扩展,以便能够计算出实际的变量名。
define two-lines
echo foo
echo $(bar)
endef
变量的值在通常的赋值语句中只能在一行中完成,但在define指令中在define指令行以后endef行之前中间所有的行都是变量值的一部分(最后一行除外,因为标示endef那一行不能认为是变量值的一部分)。前面的例子功能上等同于:
two-lines = echo foo; echo $(bar)
因为两命令之间用分号隔开,其行为很接近于两个分离的shell命令。然而,注意使用两个分离的行,意味着make请求shell两次,每一行都在独立的子shell中运行。参阅执行命令。
如果您希望使用define指令的变量定义比使用命令行定义的变量优先,您可以把define指令和override指令一块使用:
override define two-lines
foo
$(bar)
endef
参阅override指令。
6.9 环境变量
make使用的变量可以来自make的运行环境。任何make能够看见的环境变量,在make开始运行时都转变为同名同值的make变量。但是,在makefile文件中对变量的具体赋值,或使用带有参数的命令,都可以对环境变量进行重载(如果明确使用‘-e’标志,环境变量的值可以对makefile文件中的赋值进行重载,参阅选项概要,但是这在实际中不推荐使用。)
这样,通过在环境中设置变量CFLAGS,您可以实现在绝大多数makefile文件中的所有C源程序的编译使用您选择的开关。因为您知道没有makefile将该变量用于其它任务,所以这种使用标准简洁含义的变量是安全的(但这也是不可靠的,一些makefile文件可能设置变量CFLAGS,从而使环境中变量CFLAGS的值失效)。当使用递归调用的make时,在外层make环境中定义的变量,可以传递给内层的make(参阅递归调用make)。缺省方式下,只有环境变量或在命令行中定义的变量才能传递给内层make。您可以使用export指令传递其它变量,参阅与子make通讯的变量。
环境变量的其它使用方式都不推荐使用。将makefile的运行完全依靠环境变量的设置、超出makefile文件的控制范围,这种做法是不明智的,因为不同的用户运行同一个makefile文件有可能得出不同的结果。这和大部分makefile文件的意图相违背。
变量SHELL在环境中存在,用来指定用户对交互的shell的选择,因此使用变量SHELL也存字类似的问题。这种根据选定值影响make运行的方式是很不受欢迎的。所以,make将忽略环境中变量SHELL的值(在MS-DOS 和
MS-Windows中运行例外,但此时变量SHELL通常不设置值,参阅执行命令)。
6.10 特定目标变量的值
make中变量的值一般是全局性的;既,无论它们在任何地方使用,它们的值是一样的(当然,您重新设置除外);自动变量是一个例外(参阅自动变量)。
另一个例外是特定目标变量的值,这个特点允许您可以根据make建造目标的变化改变变量的定义。象自动变量一样,这些值只能在一个目标的命令脚本的上下文起作用。
可以象这样设置特定目标变量的值:
target ... : variable-assignment
或这样:
target ... : override variable-assignment
‘target ...’中可含有多个目标,如此,则设置的特定目标变量的值可在目标列表中的任一个目标中使用。‘variable-assignment’使用任何赋值方式都是有效的:递归调用型(‘=’)、静态(‘:=’)、追加(‘+=’)或条件(‘?=’)。所有出现在‘variable-assignment’中的变量能够在特定目标target ...的上下文中使用:也就是任何以前为特定目标target ...定义的特定目标变量的值在这些特定目标中都是有效的。注意这种变量值和全局变量值相比是局部的值:这两种类型的变量不必有相同的类型(递归调用vs.静态)。
特定目标变量的值和其它makefile变量具有相同的优先权。一般在命令行中定义的变量(和强制使用‘-e’情况下的环境变量)的值占据优先的地位,而使用override指令定义的特定目标变量的值则占据优先地位。
特定目标变量的值有另外一个特点:当您定义一个特定目标变量时,该变量的值对特定目标target ...的所有依赖有效,除非这些依赖用它们自己的特定目标变量的值将该变量重载。例如:
prog : CFLAGS = -g
prog : 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 特定格式变量的值
除了特定目标变量的值(参阅上小节)外,GNU make也支持特定格式变量的值。使用特定格式变量的值,可以为匹配指定格式的目标定义变量。在为目标定义特定目标变量后将搜寻按特定格式定义的变量,在为该目标的父目标定义的特定目标变量前也要搜寻按特定格式定义的变量。
设置特定格式变量格式如下:
pattern ... : variable-assignment
或这样:
pattern ... : override variable-assignment
这里的‘pattern’是%-格式。象特定目标变量的值一样,‘pattern ...’中可含有多个格式,如此,则设置的特定格式变量的值可在匹配列表中的任一个格式中的目标中使用。‘variable-assignment’使用任何赋值方式都是有效的,在命令行中定义的变量的值占据优先的地位,而使用override指令定义的特定格式变量的值则占据优先地位。例如:
%.o : CFLAGS = -O
搜寻所有匹配格式%.o的目标,并将它的变量CFLAGS的值设置为‘-0’。
7 makefile文件的条件语句
一个条件语句可以导致根据变量的值执行或忽略makefile文件中一部分脚本。条件语句可以将一个变量与其它变量的值相比较,或将一个变量与一字符串常量相比较。条件语句用于控制make实际看见的makefile文件部分,不能用于在执行时控制shell命令。
7.1条件语句的例子
下述的条件语句的例子告诉make如果变量CC的值是‘gcc’时使用一个数据库,如不是则使用其它数据库。它通过控制选择两命令行之一作为该规则的命令来工作。‘CC=gcc’作为make改变的参数的结果不仅用于决定使用哪一个编译器,而且决定连接哪一个数据库。
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o
foo $(objects) $(libs_for_gcc)
else
$(CC) -o
foo $(objects) $(normal_libs)
endif
该条件语句使用三个指令:ifeq、else和endif。
Ifeq指令是条件语句的开始,并指明条件。它包含两个参数,它们被逗号分开,并被扩在圆括号内。运行时首先对两个参数变量替换,然后进行比较。在makefile中跟在ifeq后面的行是符合条件时执行的命令;否则,它们将被忽略。
如果前面的条件失败,else指令将导致跟在其后面的命令执行。在上述例子中,意味着当第一个选项不执行时,和第二个选项连在一起的命令将执行。在条件语句中,else指令是可选择使用的。
Endif指令结束条件语句。任何条件语句必须以endif指令结束,后跟makefile文件中的正常内容。
上例表明条件语句工作在原文水平:条件语句的行根据条件要么被处理成makefile文件的一部分或要么被忽略。这是makefile文件重大的语法单位(例如规则)可以跨越条件语句的开始或结束的原因。
当变量CC的值是gcc,上例的效果为:
foo: $(objects)
$(CC) -o
foo $(objects) $(libs_for_gcc)
当变量CC的值不是gcc而是其它值的时候,上例的效果为:
foo: $(objects)
$(CC) -o
foo $(objects) $(normal_libs)
相同的结果也能使用另一种方法获得:先将变量的赋值条件化,然后再使用变量:
libs_for_gcc = -lgnu
normal_libs =
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
foo: $(objects)
$(CC) -o
foo $(objects) $(libs)
7.2条件语句的语法
对于没有else指令的条件语句的语法为:
conditional-directive
text-if-true
endif
‘text-if-true’可以是任何文本行,在条件为‘真’时它被认为是makefile文件的一部分;如果条件为‘假’,将被忽略。完整的条件语句的语法为:
conditional-directive
text-if-true
else
text-if-false
endif
如果条件为‘真’,使用‘text-if-true’;如果条件为‘假’,使用‘text-if-false’。‘text-if-false’可以是任意多行的文本。
关于‘conditional-directive’的语法对于简单条件语句和复杂条件语句完全一样。有四种不同的指令用于测试不同的条件。下面是指令表:
ifeq (arg1, arg2)
ifeq 'arg1' 'arg2'
ifeq "arg1" "arg2"
ifeq "arg1" 'arg2'
ifeq 'arg1' "arg2"
扩展参数arg1、arg2中的所有变量引用,并且比较它们。如果它们完全一致,则使用‘text-if-true’,否则使用‘text-if-false’(如果存在的话)。您经常要测试一个变量是否有非空值,当经过复杂的变量和函数扩展得到一个值,对于您认为是空值,实际上有可能由于包含空格而被认为不是空值,由此可能造成混乱。对于此,您可以使用strip函数从而避免空格作为非空值的干扰。例如:
ifeq ($(strip $(foo)),)
text-if-empty
endif
即使$(foo)中含有空格,也使用‘text-if-empty’。
ifneq (arg1, arg2)
ifneq 'arg1' 'arg2'
ifneq "arg1" "arg2"
ifneq "arg1" 'arg2'
ifneq 'arg1' "arg2"
扩展参数arg1、arg2中的所有变量引用,并且比较它们。如果它们不同,则使用‘text-if-true’,否则使用‘text-if-false’(如果存在的话)。
ifdef variable-name
如果变量‘variable-name’是非空值,‘text-if-true’有效,否则,‘text-if-false’有效(如果存在的话)。变量从没有被定义过则变量是空值。注意ifdef仅仅测试变量是否有值。它不能扩展到看变量是否有非空值。因而,使用ifdef测试所有定义过的变量都返回‘真’,但那些象‘foo=’情况除外。测试空值请使用ifeq($(foo),)。例如:
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
设置‘frobozz'的值为‘yes', 而::
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
设置‘frobozz' 为‘no'。
ifndef variable-name
如果变量‘variable-name’是空值,‘text-if-true’有效,否则,‘text-if-false’有效(如果存在的话)。
在指令行前面允许有多余的空格,它们在处理时被忽略,但是不允许有Tab(如果一行以Tab开始,那么该行将被认为是规则的命令行)。除此之外,空格和Tab可以插入到行的任何地方,当然指令名和参数中间除外。以‘#’开始的注释可以在行的结尾。
在条件语句中另两个有影响的指令是else和endif。这两个指令以一个单词的形式出现,没有任何参数。在指令行前面允许有多余的空格,空格和Tab可以插入到行的中间,以‘#’开始的注释可以在行的结尾。
条件语句影响make使用的makefile文件。如果条件为‘真’,make读入‘text-if-true’包含的行;如果条件为‘假’,make读入‘text-if-false’包含的行(如果存在的话);makefile文件的语法单位,例如规则,可以跨越条件语句的开始或结束。
当读入makefile文件时,Make计算条件的值。因而您不能在测试条件时使用自动变量,因为他们是命令执行时才被定义(参阅自动变量)。
为了避免不可忍受的混乱,在一个makefile文件中开始一个条件语句,而在另外一个makefile文件中结束这种情况是不允许的。然而如果您试图引入包含的makefile文件不中断条件语句,您可以在条件语句中编写include指令。
7.3测试标志的条件语句
您可以使用变量MAKEFLAGS和findstring函数编写一个条件语句,用它来测试例如‘-t’等的make命令标志(参阅字符串替换和分析的函数)。这适用于仅使用touch标志不能完全更改文件的时间戳的场合。
findstring函数检查一个字符串是否为另一个字符串的子字符串。如果您要测试‘-t’标志,使用‘-t’作为第一个字符串,将变量MAKEFLAGS的值作为另一个字符串。例如下面的例子是安排使用‘ranlib –t’完成一个档案文件的更新:
archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
+touch
archive.a
+ranlib
-t archive.a
else
ranlib
archive.a
endif
前缀‘+’表示这些命令行是递归调用行,即使是用‘-t’标志它们一样要执行。参阅递归调用make。
8 文本转换函数
函数允许您在makefile文件中处理文本、计算文件、操作使用命令等。在函数调用时您必须指定函数名以及函数操作使用的参数。函数处理的结果将返回到makefile文件中的调用点,其方式和变量替换一样。
8.1函数调用语法
函数调用和变量引用类似,它的格式如下:
$(function arguments)
或这样:
${function arguments}
这里‘function’是函数名,是make内建函数列表中的一个。当然您也可以使用创建函数call创建的您自己的函数。‘arguments’是该函数的参数。参数和函数名之间是用空格或Tab隔开,如果有多个参数,它们之间用逗号隔开。这些空格和逗号不是参数值的一部分。包围函数调用的定界符,无论圆括号或大括号,可以在参数中成对出现,在一个函数调用中只能有一种定界符。如果在参数中包含变量引用或其它的函数调用,最好使用同一种定界符,如写为‘$(subst a,b,$(x))', 而不是 `$(subst a,b,${x})'。这是因为这种方式不但比较清楚,而且也有在一个函数调用中只能有一种定界符的规定。
为每一个参数写的文本经过变量替换或函数调用处理,最终得到参数的值,这些值是函数执行必须依靠的文本。另外,变量替换是按照变量在参数中出现的次序进行处理的。
逗号和不成对出现的圆括号、大括号不能作为文本出现在参数中,前导空格也不能出现在第一个参数中。这些字符不能被变量替换处理为参数的值。如果需要使用这些字符,首先定义变量comma和space,它们的值是单独的逗号和空格字符,然后在需要的地方因用它们,如下例:
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
# bar is now `a,b,c'.
这里函数subst的功能是将变量foo中的空格用逗号替换,然后返回结果。
8.2字符串替换和分析函数
这里有一些用于操作字符串的函数:
$(subst from,to,text)
在文本‘text’中使用‘to’替换每一处‘from’。例如:
$(subst ee,EE,feet on the street)
结果为‘fEEt on the street’。
$(patsubst pattern,replacement,text)
寻找‘text’中符合格式‘pattern’的字,用‘replacement’替换它们。这里‘pattern’中包含通配符‘%’,它和一个字中任意个数的字符相匹配。如果‘replacement’中也含有通配符‘%’,则这个‘%’被和‘pattern’中通配符‘%’匹配的文本代替。在函数patsubst中的‘%’可以用反斜杠(‘\’)引用。引用字符‘%’的反斜杠可以被更多反斜杠引用。引用字符‘%’和其它反斜杠的反斜杠在比较文件名或有一个stem(径)代替它之前从格式中移出。使用反斜杠引用字符‘%’不会带来其它麻烦。例如,格式‘the\%weird\\%pattern\\'是‘the%weird\' 加上通配符‘%'然后和字符串‘pattern\\'连接。最后的两个反斜杠由于不能影响任何统配符‘%’所以保持不变。在字之间的空格间被压缩为单个空格,前导以及结尾空格被丢弃。例如:
$(patsubst %.c,%.o,x.c.c bar.c)
的结果为:‘x.c.o bar.o'。替换引用是实现函数patsubst功能一个简单方法:
$(var:pattern=replacement)
等同于
:
$(patsubst pattern,replacement,$(var))
另一个通常使用的函数patsubst的简单方法是:替换文件名的后缀。
$(var:suffix=replacement)
等同于:
$(patsubst %suffix,%replacement,$(var))
例如您可能有一个OBJ文件的列表:
objects = foo.o bar.o baz.o
要得到这些文件的源文件,您可以简单的写为:
$(objects:.o=.c)
代替规范的格式:
$(patsubst %.o,%.c,$(objects))
$(strip string)
去掉前导和结尾空格,并将中间的多个空格压缩为单个空格。这样,‘$(strip a
b c )'结果为‘a b c’。函数strip和条件语句连用非常有用。当使用ifeq或ifneq把一些值和空字符串‘’比较时,您通常要将一些仅由空格组成的字符串认为是空字符串(参阅makefile中的条件语句)。如此下面的例子在实现预期结果时可能失败:
.PHONY: all
ifneq
"$(needs_made)" ""
all: $(needs_made)
else
all:;@echo 'Nothing to make!'
endif