第七部分 使用变量 (下)

2024-01-07 20:35:49

目录

三、变量高级用法

四、追加变量值

五、override 指示符

六、多行变量

七、环境变量

八、目标变量

九、模式变量


三、变量高级用法

????????这里介绍两种变量的高级使用方法,第一种是变量值的替换。我们可以替换变量中的共有的 部分,其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以 “a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束 符”。

???????? 还是看一个示例吧:

foo := a.o b.o c.o

bar := $(foo:.o=.c)

????????这个示例中,我们先定义了一个“$(foo)”变量,而第二行的意思是把“$(foo)”中所 有以“.o”字串“结尾”全部替换成“.c”,所以我们的“$(bar)”的值就是“a.c b.c c.c”。

???????? 另外一种变量替换的技术是以“静态模式”(参见前面章节)定义的,如:

foo := a.o b.o c.o

bar := $(foo:%.o=%.c)

????????这依赖于被替换字串中的有相同的模式,模式中必须包含一个“%”字符,这个例子同 样让$(bar)变量的值为“a.c b.c c.c”。

????????第二种高级用法是——“把变量的值再当成变量”。先看一个例子:

x = y

y = z

a := $($(x))

在这个例子中,$(x)的值是“y”,所以$($(x))就是$(y),于是$(a)的值就是“z”。(注意, 是“x=y”,而不是“x=$(y)”)

我们还可以使用更多的层次:

x = y

y = z

z = u

a := $($($(x)))

这里的$(a)的值是“u”,相关的推导留给读者自己去做吧。

让我们再复杂一点,使用上“在变量定义中使用变量”的第一个方式,来看一个例子:

x = $(y)

y = z

z = Hello

a := $($(x))

这里的$($(x))被替换成了$($(y)),因为$(y)值是“z”,所以,最终结果是:a:=$(z),也 就是“Hello”。

再复杂一点,我们再加上函数:

x = variable1

variable2 := Hello

y = $(subst 1,2,$(x))

z = y

a := $($($(z)))

这 个 例 子 中 , “$($($(z)))” 扩 展 为 “$($(y))” , 而 其 再 次 被 扩 展 为 “$($(subst 1,2,$(x)))”。$(x)的值是“variable1”,subst 函数把“variable1”中的所有“1”字 串替换成“2”字串,于是,“variable1”变成“variable2”,再取其值,所以,最终, $(a)的值就是$(variable2)的值——“Hello”。(喔,好不容易)

在这种方式中,或要可以使用多个变量来组成一个变量的名字,然后再取其值:

first_second = Hello

a = first

b = second

all = $($a_$b)

这里的“$a_$b”组成了“first_second”,于是,$(all)的值就是“Hello”。

再来看看结合第一种技术的例子:

a_objects := a.o b.o c.o

1_objects := 1.o 2.o 3.o

sources := $($(a1)_objects:.o=.c)

这个例子中,如果$(a1)的值是“a”的话,那么,$(sources)的值就是“a.c b.c c.c”; 如果$(a1)的值是“1”,那么$(sources)的值是“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))

这个示例中,如果定义了“do_sort”,那么:foo := $(sort a d b g q c),于是$(foo) 的值就是“a b c d g q”,而如果没有定义“do_sort”,那么:foo := $(sort a d bg q c),调用的就是 strip 函数。

当然,“把变量的值再当成变量”这种技术,同样可以用在操作符的左边:

dir = foo

$(dir)_sources := $(wildcard $(dir)/*.c)

define $(dir)_print

lpr $($(dir)_sources)

endef

这个例子中定义了三个变量:“dir”,“foo_sources”和“foo_print”。

四、追加变量值

我们可以使用“+=”操作符给变量追加值,如:

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

objects += another.o

于是,我们的$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o 被追加进去了)

使用“+=”操作符,可以模拟为下面的这种例子:

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

objects := $(objects) another.o

所不同的是,用“+=”更为简洁。

如果变量之前没有定义过,那么,“+=”会自动变成“=”,如果前面有变量定义,那么“+=” 会继承于前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符, 如:

variable := value

variable += more

等价于:

variable := value

variable := $(variable) more

但如果是这种情况: variable = value variable += more 由于前次的赋值符是“=”,所以“+=”也会以“=”来做为赋值,那么岂不会发生变量的递 补归定义,这是很不好的,所以 make 会自动为我们解决这个问题,我们不必担心这个问题。

五、override 指示符

如果有变量是通常make的命令行参数设置的,那么Makefile中对这个变量的赋值会被忽略。如果你想在 Makefile 中设置这类参数的值,那么,你可以使用“override”指示符。其语 法是:

override <variable>=<value>

override<variable> :=<value>

当然,你还可以追加:

override<variable> +=<more text>

对于多行的变量定义,我们用 define 指示符,在 define 指示符前,也同样可以使用 ovveride 指示符,如:

override define foo

bar

endef

六、多行变量

????????还有一种设置变量值的方法是使用 define 关键字。使用 define 关键字设置变量的值可 以有换行,这有利于定义一系列的命令(前面我们讲过“命令包”的技术就是利用这个关键 字)。

????????define 指示符后面跟的是变量的名字,而重起一行定义变量的值,定义是以 endef 关 键字结束。其工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字,或是其 它变量。因为命令需要以[Tab]键开头,所以如果你用 define 定义的命令变量中没有以[Tab] 键开头,那么 make 就不会把其认为是命令。

下面的这个示例展示了 define 的用法:

define two-lines

echo foo

echo $(bar)

endef

七、环境变量

????????make 运行时的系统环境变量可以在 make 开始运行时被载入到 Makefile 文件中,但是如果 Makefile 中已定义了这个变量,或是这个变量由 make 命令行带入,那么系统的环境变 量的值将被覆盖。(如果 make 指定了“-e”参数,那么,系统环境变量将覆盖 Makefile 中 定义的变量)

???????? 因此,如果我们在环境变量中设置了“CFLAGS”环境变量,那么我们就可以在所有的 Makefile 中使用这个变量了。这对于我们使用统一的编译参数有比较大的好处。如果 Makefile 中定义了 CFLAGS,那么则会使用 Makefile 中的这个变量,如果没有定义则使用系 统环境变量的值,一个共性和个性的统一,很像“全局变量”和“局部变量”的特性。

????????当 make 嵌套调用时(参见前面的“嵌套调用”章节),上层 Makefile 中定义的变量会 以系统环境变量的方式传递到下层的 Makefile 中。当然,默认情况下,只有通过命令行设 置的变量会被传递。而定义在文件中的变量,如果要向下层 Makefile 传递,则需要使用 exprot 关键字来声明。(参见前面章节)

???????? 当然,我并不推荐把许多的变量都定义在系统环境中,这样,在我们执行不用的 Makefile 时,拥有的是同一套系统变量,这可能会带来更多的麻烦。

八、目标变量

????????前面我们所讲的在 Makefile 中定义的变量都是“全局变量”,在整个文件,我们都可 以访问这些变量。当然,“自动化变量”除外,如“$ : : overide 可以是前面讲过的各种赋值表达式,如“=”、“:=”、“+=” 或是“?=”。第二个语法是针对于 make 命令行带入的变量,或是系统环境变量。这个特性 非常的有用,当我们设置了这样一个变量,这个变量会作用到由这个目标所引发的所有的规 则中去。如:

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

$(CC) $(CFLAGS) prog.o foo.o bar.o

prog.o : prog.c

$(CC) $(CFLAGS) prog.c

foo.o : foo.c

$(CC) $(CFLAGS) foo.c

bar.o : bar.c

$(CC) $(CFLAGS) bar.c

????????在这个示例中,不管全局的$(CFLAGS)的值是什么,在 prog 目标,以及其所引发的所有 规则中(prog.o foo.o bar.o 的规则),$(CFLAGS)的值都是“-g”

九、模式变量

????????在 GNU 的 make 中,还支持模式变量(Pattern-specific Variable),通过上面的目标 变量中,我们知道,变量可以定义在某个目标上。模式变量的好处就是,我们可以给定一种 “模式”,可以把变量定义在符合这种模式的所有目标上。

????????我们知道,make 的“模式”一般是至少含有一个“%”的,所以,我们可以以如下方式 给所有以[.o]结尾的目标定义目标变量:

%.o : CFLAGS = -O

同样,模式变量的语法和“目标变量”一样:

: : override

override 同样是针对于系统环境传入的变量,或是 make 命令行指定的变量。

文章来源:https://blog.csdn.net/qq_42700289/article/details/135437895
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。