Makefile 变量
变量的概念
在 Makefile中的定义的变量,就像是C/C++语言中的宏一样,他可以代表一个文本字符串也可以是数字,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。在Makefile中,变量可以使用在“目标”,“依赖目标”,“命令”或是 Makefile的其它部分b中。
变量的命名
变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有“:”、“#”、“=”或是空字符(空格、回车等)。变量区分大小写,传统的Makefile的变量名是全大写的命名方式,通常使用大小写搭配的方式命名变量例如 Flags。这样可以避免和系统的变量冲突,而发生意外的事情。还有一些如“ < ” 、 “ <”、“ <”、“@” “^”等自动化变量。
变量的使用
变量在声明时需要给予初值,而在使用该变量时,需要给在变量名前 加上“ ” 符 号 , 但 最 好 用 小 括 号 “ ( ) ” 或 是 大 括 号 “ ” 把 变 量 给 包 括 起 来 , 一 般 用 括 起 来 。 如 果 你 要 使 用 真 实 的 “ ”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来,一般用{}括起来。如果你要使用真实的“ ”符号,但最好用小括号“()”或是大括号“”把变量给包括起来,一般用括起来。如果你要使用真实的“”字符,那么你需要用“$$”来表示。变量可以使用在许多地方,如规则中的“目标”、“依赖”、“命令”以及新的变量中。
obj=main.c
src=${obj}
#展开src = main.c
在定义变量的值时,我们可以使用其它变量来构造变量的值,在Makefile中有两种方式来在用变量定义变量的值。
先看第一种方式,也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好。使用这种方式要注意,变量的值是最终赋值的值,例如
inc=${src}
src=${obj}
obj= main.c
all:
echo ${inc}
下面看个例程
A=${B}
B=${A}
这会让make陷入无限的变量展开过程中去,当然,我们的make是有能力检测这样的定义,并会报错。还有就是如果在变量中使用函数,那么,这种方式会让我们的make运行时非常慢,更糟糕的是,他会使用得两个make的函数“wildcard”和“shell”发生不可预知的错误。因为你不会知道这两个函数会被调用多少次。
我们通过使用“:=”操作符来定义变量,
foo1:=blue
foo2:=${foo1} pig
all:
echo ${foo2}
#等价于 --> blue pig
#前后的变量不能使用后面变量的值
foo2:=${foo1} pig
foo1:=blue
all:
echo ${foo2}
#等价于 --> pig
还有一个比较有用的操作符是“?=”,先看示例:
FOO ?= bar
其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
变量的替换
我们可以替换变量中的共有的部分,其格式是“ ( v a r : a = b ) ” 或 是 “ (var:a=b)”或是“ (var:a=b)”或是“{var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。
foo := a.o b.o c.o
bar :=
(
f
o
o
:
.
o
=
.
c
)
这
个
示
例
中
,
我
们
先
定
义
了
一
个
“
(foo:.o=.c) 这个示例中,我们先定义了一个“
(foo:.o=.c)这个示例中,我们先定义了一个“(foo)”变量,而第二行的意思是把“
(
f
o
o
)
”
中
所
有
以
“
.
o
”
字
串
“
结
尾
”
全
部
替
换
成
“
.
c
”
,
所
以
我
们
的
“
(foo)”中所有以“.o”字串“结尾”全部替换成“.c”,所以我们的“
(foo)”中所有以“.o”字串“结尾”全部替换成“.c”,所以我们的“(bar)”的值就是“a.c b.c c.c”。
另外一种变量替换的技术是以“静态模式”(参见前面章节)定义的,如:foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
override指示符
通常在执行 make 时,如果通过命令行定义了一个变量,那么它将替代在 Makefile中出现的同名变量的定义。
就是说,对于一个在 Makefile 中使用常规方式(使用“=”、“:=”或者“define”)定义的变量,我们可以在执行 make 时通过命令行方式重新指定这个变量的值,命令行指定的值将替代出现在 Makefile 中此变量的值。
如果不希望命令行指定的变量值替代在 Makefile 中的变量定义,那么我们需要在 Makefile 中使用指示符“override”来对这个变量进行声明。
override作用
- 保护makefile中定义的变量的值;
- 提供一种在makefile中增加或者修改命令行参数的方式;
实际情况下,我们经常会有这种需求:通过命令行指定一些附加的参数选项,对于一些通用的参数选项在makefile中指定.
保护makefile中定义变量值示例
1.1 没有使用override的情况
make命令行指定的变量值将会覆盖makefile中定义的同名的变量值
SRCS := A.c B.c C.c
all:
@echo "SRCS: " $(SRCS)
#执行make SRC=no
#输出的值为no
1.2 使用override的情况
make命令行指定的变量值将不会覆盖makefile中定义的同名的变量值,所以override有保护makefile中变量值不被命令行参数修改的作用。
override SRCS := A.c B.c C.c
all:
@echo "SRCS: " $(SRCS)
1.3 override追加变量
#使用override进行追加的变量的原来指定的值不会被命令行参数覆盖,而且会追加命令行指定的值
override CFLAGS += -g
all:
@echo $(CFLAGS)
变量的追加
通过使用“+=”操作符来对一个变量进行追加赋值
例如
src=main.o led.o key.o
src+=muc.o
all:
echo ${src}
#等价于:-->main.o led.o key.o muc.o
环境变量
make 运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中已定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖。(如果make指定了“-e”参数,那么,系统环境变量将覆盖Makefile中定义的变量)
因此,如果我们在环境变量中设置了“CFLAGS”环境变量,那么我们就可以在所有的Makefile中使用这个变量了。这对于我们使用统一的编译参数有比较大的好处。如果Makefile中定义了CFLAGS,那么则会使用Makefile中的这个变量,如果没有定义则使用系统环境变量的值,一个共性和个性的统一,很像“全局变量”和“局部变量”的特性。 当make嵌套调用时(参见前面的“嵌套调用”章节),上层Makefile中定义的变量会以系统环境变量的方式传递到下层的Makefile中。当然,默认情况下,只有通过命令行设置的变量会被传递。而定义在文件中的变量,如果要向下层 Makefile传递,则需要使用exprot关键字来声明
define 用法
makefile里可能会用到define来打包一些可能会重用的指令,但是因为makefile里实际上会重用代码的情况并不多…所以,define是一个没怎么设计的挺难用的东西;有一点需要注意的是在define-endef范围内的变量定义和指令的执行,在该范围内,变量定义是无效的,在define段执行时回座位字符串展开;指令的执行则是需要注意一下cmd
和
(
s
h
e
l
l
c
m
d
)
的
区
别
,
区
别
是
‘
c
m
d
‘
在
执
行
到
当
前
指
令
的
时
候
不
展
开
,
而
(shell cmd)的区别,区别是`cmd`在执行到当前指令的时候不展开,而
(shellcmd)的区别,区别是‘cmd‘在执行到当前指令的时候不展开,而(shell cmd)在执行到当前指令的时候是展开为指令结果的;
define 类似定义函数
define output
A=pwd#作为字符串输出
A=`pwd`#作为字符串输出
A=$(shell pwd)#只有这个A的值是pwd展开之后的值,但是!
echo $(A)#这句的输出是空的,上一句A=$(shell pwd)并不是存在一个被赋值的变量A,
#而是define在执行的时候A=是一个字符串,然后$(shell pwd)在echo语句中也被直接展开为了字符串的形式;
echo pwd#输出是echo pwd pwd,也就是pwd不展开为shell指令
echo `pwd`#输出是echo `pwd` a/b/c,也就是先输出指令字符串,随后切到shell执行pwd
echo $(shell pwd)#输出是echo a/b/c a/b/c,在这句指令显示的阶段$(shell pwd)就已经展开为对应的字符串了
endef
all:
$(call output)
模式变量
在GNU的make中,还支持模式变量(Pattern-specific Variable),通过上面的目标变量中,我们知道,变量可以定义在某个目标上。模式变量的好处就是,我们可以给定一种“模式”,可以把变量定义在符合这种模式的所有目标上。
我们知道,make的“模式”一般是至少含有一个“%”的,所以,我们可以以如下方式给所有以[.o]结尾的目标定义目标变量:
%.o : CFLAGS = -O
同样,模式变量的语法和“目标变量”一样:
<pattern …> :
<pattern …> : override override
例如
%.o:%.c
自动化变量
$@:表示规则中的目标文件名
$^:表示规则中的所有依赖文件名
$<:表示规则中的第一个依赖文件名