makefile中的变量

makefile中的变量

在Makefile中的定义的变量,就像是C/C++语言中的一样,他代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。在Makefile中,变量可以使用在“目标”,“依赖目标”, “命令”或是Makefile的其它部分中。
变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有“:”、“#”、“=”或是空字符(空格、回车等)。变量是区分英文字母大小写的,“foo”、“Foo”和“FOO”是三个不同的变量名。传统的Makefile的变量名是全大写的命名方式,但推荐使用大小写搭配的变量名,如: MakeFlags。这样可以避免和系统的变量冲突,而发生意外的事情。

变量的使用

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来。如果你要使用真实的“$”字符,那么你需要用“$$”来表示。
如:

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

$(objects) : defs.h

变量会在使用它的地方精确地展开,就像C/C++中的宏一样,例如:

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

展开后得到:

prog.o : prog.c
        cc -c prog.c
变量的赋值方式

在makefile中,变量有4种赋值方式,分别是立即赋值(:=)、延迟赋值(=)、条件赋值(?=)及附加赋值(+=)。
1. 立即赋值 a:=b
对于这种赋值方式,变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
例如:

x := XXX
y := $(x)
x := YYY

在上例中,y的值将会是 XXX ,而不是 YYY。
2. 延迟赋值 a=b
该赋值方式是最基本的赋值(最后才展开)
make会将整个makefile展开后,再决定变量的值。也就是说,变量的值展开是在最后, 使我们可以在最后才指定变量的值。
例如:

x = XXX
y = $(x)
x = YYY

在上例中,y的值将会是 YYY ,而不是 XXX。
3. 条件赋值 a?=b
对于该种赋值方式, 如果没有被赋值过就赋予等号后面的值,否则不做任何操作。
4. 附加赋值 a+=b
当变量从前没有被定义过, +=和=是一样的,它定义一个递归展开的变量,但是,当变量已经有定义的时候,+=只是简单的进行字符的添加工作。
如果起初你用:=定义变量,那么+=只是利用变量的当前值进行添加
如果起初用=定义变量,+=的行为就变得有些古怪,它并不会在使用+=的地方马上进行变量展开,而是会把展开工作推后,直到它找到最后变量的定义,这和=定义变量的行为是类似的。

变量值的替换

我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以“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”。

override指示符

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

override <variable> = <value>;
override <variable> := <value>;

当然,你还可以追加:

override <variable> += <more text>;
多行变量

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

define two-lines
echo foo
echo $(bar)
endef

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

override define two-lines
foo 
$(bar)
endef
环境变量

make运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中已定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖。(如果make指定了“-e”参数,那么,系统环境变量将覆盖Makefile中定义的变量)
因此,如果我们在环境变量中设置了“CFLAGS”环境变量,那么我们就可以在所有的Makefile中使用这个变量了。这对于我们使用统一的编译参数有比较大的好处。
如果在Makefile中定义了CFLAGS,那么则会使用Makefile中的这个变量,如果没有定义则使用系统环境变量的值,一个共性和个性的统一,很像“全局变量”和“局部变量”的特性。
当make嵌套调用时,上层Makefile中定义的变量会以系统环境变量的方式传递到下层的Makefile 中。当然,默认情况下,只有通过命令行设置的变量会被传递。而定义在文件中的变量,如果要向下层Makefile传递,则需要使用export关键字来声明。
并不推荐把许多的变量都定义在系统环境中,这样,在我们执行不同的Makefile时,拥有的是同一套系统变量,这可能会带来更多的麻烦。

自动变量

为了方便扩展, 经常会看到类似的一些奇怪符号。

1.$@
$@ 指代当前目标,即make 命令当前构建的那个目标。比如,make foo 的 $@ 就指代 foo。

a.txt b.txt: 
    touch $@

等同于下面的写法。

a.txt:
    touch a.txt
b.txt:
    touch b.txt

2.$<
$< 指代第一个依赖条件。
如果依赖对象是一个序列,依次代表每一个依赖条件

a.txt: b.txt c.txt
    cp $< $@ 

等同于下面的写法。

    cp b.txt a.txt 
    cp c.txt a.txt 

3.$^
$^ 指代所有前置条件,之间以空格分隔。
比如,规则为 t: p1 p2,那么 $^ 就指代 p1 p2 。

4.$?
$? 指代比目标更新的所有前置条件,之间以空格分隔。
比如,规则为 t: p1 p2,若其中 p2 的时间戳比 t 新,$?就指代p2。

5.$*
$* 指代匹配符 % 匹配的部分,
比如 %.txt 匹配 f1.txt 中的 f1 ,$* 就表示 f1。

6.$(@D)和 $(@F)
$(@D) 和 $(@F) 分别指向 $@ 的目录名和文件名。
比如,$@ 是 src/input.c,那么$(@D) 的值为 src ,$(@F) 的值为 input.c。

7.$(< D) 和 $(< F)
$(< D) 和 $(< F) 分别指向 $< 的目录名和文件名。

目标变量

在Makefile中定义的变量都是“全局变量”,在整个文件,我们都可以访问这些变量。当然,“自动化变量”除外,如“$<”等这种类量的自动化变量就属于“规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义。
当然,同样可以为某个目标设置局部变量,这种变量被称为“Target-specific Variable”,它可以和“全局变量”同名,因为它的作用范围只在这条规则以及连带规则中,所以其值也只在作用范围内有效。而不会影响规则链以外的全局变量的值。
其语法是:

<target ...> : <variable-assignment>
<target ...> : override <variable-assignment>

< variable-assignment>;可以是前面讲过的各种赋值表达式,如“=”、“:=”、“+=”或是“?=”。第二个语法是针对于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

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

<pattern ...> : <variable-assignment>;
<pattern ...> : override <variable-assignment>;

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

参考:
1.https://www.jianshu.com/p/5982ccb87af0
2.http://wiki.ubuntu.org.cn/%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile:%E4%BD%BF%E7%94%A8%E5%8F%98%E9%87%8F

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值