Makefile变量使用

Makefile变量赋值符

Makefile变量赋值符类似于编程语言中对变量进行赋值的符号,常见的有 = 号,makefile中我目前所知道的有四种赋值符号,分别如下:

  • =:这是最普通的赋值符号,赋值完成后使用变量会变成替换=之后的内容
  • := :这种方式定义的变量,前面定义的变量不可以使用后边定义的变量,其实可以防止递归定义变量带来的缺陷,下文会有解释。
  • ?= :这种方式定义的变量,如果前面已经定义过,那么此条定义语句就没有任何作用,也就是只有首次定义才会有效
  • += :追加定义变量
    接下来详细解释下每种定义变量的区别
    1.最普通的= 定义变量,可以在任何位置定义变量,也就是说不一定要先定义,下面请看一个例子
    1
    2
    3
    foo=$(bar)
    bar=$(ugh)
    ugh=Huh?

那么最后foo的值就是Huh? ,这也就是=定义变量之前先引用之后定义的变量。
缺点:这种方式定义变量有明显的缺陷,就是递归定义,请看如下例子:

1
CFLAGS=$(CFLAGS) -O

1
2
A=$(B)
B=$(A)

这样子就会使得make陷入无限的变量展开过程中去,当然make具备检测这种情况的能力,会报错,为了避免上述情况发生,我们就可以使用”:=”符号定义变量
2.上面对”:=”已经有了初步介绍,下边请看详细的例子解释:

1
2
3
x :=foo
y :=$(x) bar
x := later

最后的结果就是 y的值是”foo bar” ,x是”later”

1
2
y :=$(x) bar
x :=later

最后的结果就是 y的值是”bar” ,x是”later”
3.接下来说一下追加定义变量符号 “+=”

1
2
obj=a.o b.o
obj+=c.o

最终obj结果就是”a.o b.o c.o”,其等价于

1
2
obj=a.o b.o
obj :=$(obj) c.o

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

1
2
variable := value
variable += more

等价于

1
2
variable := value
variable := $(variable) more

但如果是这种情况:

1
2
variable = value
variable += more

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

变量的高级用法

变量值的替换
我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。
例子:

1
2
foo := a.o b.o c.o
bar := $(foo:.o=.c)

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

1
2
3
4
x=y
y=Hello

var=$($(x))

这样子其实就是个嵌套取变量内容,最终var=Hello,这一点有点类似于C语言中的取地址符号&,当然这也可以使用更多层次

override 指示符

使用override指示符定义的变量,可以忽略make命令通过命令行参数传入的变量的值,覆盖命令行参数传值的作用。
示例:

1
2
3
4
5
6
7
8
9
10
VAR=Hello override
target:
echo $(VAR)
```

使用make VAR=Ignore命令,也就是传值给VAR变量,结果显示如下:

```Makefile
echo Ignore
Ignore

也就是说命令行参数传递变量方式会覆盖我们内部定义的变量。
那么我们使用override关键字定义的变量呢?

1
2
3
override VAR=Hello override
target:
echo $(VAR)

同样使用上边的make命令,结果如下:

1
2
echo Hello override
Hello override

定义多行变量

定义多行变量一般都是用在多行命令中来,使用define关键字可以定义一个变量的值为多行命令
示例:

1
2
3
4
5
6
7
define two_echo
echo "Hello define!"
echo "Hello end!"
endef

target:
$(two_echo)

结果如下:

1
2
3
4
echo "Hello define!"
Hello define!
echo "Hello end!"
Hello end!

目标变量

见名思意,目标变量是仅仅只针对于某个目标而定义的变量,特点是不会被全局变量所覆盖
示例:

1
2
3
4
5
6
7
8
9
target1:var=i am target1

var=Hello Target varible

target1:
echo $(var)

target2:
echo $(var)

如果使用make target1命令,结果显示:

1
2
echo i am target1
i am target1

如果是make target2命令,结果显示:

1
2
echo Hello Target varible
Hello Target varible

也就是说目标变量针对于某个目标下面的命令有效

模式变量

其实这个和目标变量很类似,目标变量是针对某种目标,模式变量是针对某种模式,比如make支持的%模式,%.o就是所有以.o结尾的文件

1
%.o:var=hello

那么接下来所有以.o结尾的目标使用的变量var都是hello