-
前言
-
变量
- 替换是一对一的替换。
- 有的版本管变量叫做宏。和
C/C++
的宏类似。
-
读取
- 读取完
make
并构成图后,变量值已确定。 recipe
中变量执行时展开。
- 读取完
-
变量定义
- 变量可包含除了
: # =
及空白字符以外的字符。 - 常用为字母数字下划线。
- 父子
SHELL
传递的变量需要考虑兼容。毕竟SHELL
也会用到。 - 大小写敏感。
- 小写变量内部使用,大写变量用于父子传递。
- 变量可包含除了
-
特殊变量
- 点开头的保留为
make
内置变量。 - 单字符的自变量和普通变量。
- 自变量普通变量都是变量,都可以使用相同的方式引用。
$(VAR),${VAR}
- 点开头的保留为
-
recipe
中的变量- 自变量的解析略微不同。自变量一般是在
recipe
部分,执行时解析。 - 也可以通过声明二次解析,让
prerequisites
也支持执行时解析。
- 自变量的解析略微不同。自变量一般是在
-
-
变量引用
-
两类变量
-
分类
- 延迟扩张和立即扩张两种类型。
- 前者可以延迟递归扩张容易出错,后者是立即扩张更精确。
-
延迟扩张缺点一
OK=$(OK) -o
这个使用的时候则会导致死循环。- 这种延迟扩张会等到使用的时候才演算值,用的时候会报错,这个可以看成没有尽头的递归。
-
延迟扩张缺点二
- 在每次使用内置函数的时候,每次都会执行调用。
- 如果是通配符或者是
SHELL
这种。可能时时刻刻都在发生变化。 - 每次都进行调用会降低效率。
-
立即扩张
- 两种格式都一样
:=,::=
,后者符合POSIX
标准。 - 在定义的时候值就已经确定了。没有所谓的引用。
- 更快更准确。
- 两种格式都一样
-
使用空表字符
- 变量定义前置空白去除。
- 后置空白也去除。
- 中间空白合并成一个。
- 可以使用在末尾添加注释的方式定义多个空白字符的变量。
aaa:=
表示一个空白字符。aaa:= # comment
也是一个字符。bbb:= $(aaa) #comment
表示两个字符。bbb:= /usr/bin $comment
表示四个字符。
-
条件定义
?=
的含义是,如果变量没有定义就定义,定义了就忽略。- 和
ifeq ($(origin var),undefined)
一样的效果。
-
-
灵活定义变量
-
变量来源
-
变量定义
=
递归扩张变量。:=,::=
立即扩张变量。CURDIR,MAKE
内置初始化变量。$@
执行时确定自变量。?=
没定义变量则定义这个变量。!=
右边是脚本,值是执行结果,这个是递归变量,结果不能包括$
,不然最好还是使用$(shell cmd)
.对于shell
函数可以使用.SHELLSTATUS
获取指令的执行结果。不过好像是版本原因!=
没用。
-
+=
-
说明
- 末尾添加。
-
延迟扩张
- 如果之前没有定义就是延迟扩张。
- 如果之前定义了且是一个延迟扩张类型,就是延迟扩张。
-
立即扩张
- 之前定义了且是一个理解扩张类型,就是立即扩张。
-
延迟和非延迟
- 延迟会在真正使用的时候,也就是执行或者是在立即扩张的上下文下递归搜索。
- 非延迟扩张会在定义变量前就计算好值。
- 非延迟就是定义了变量后再填充对应的值,如果引用自身,就会造成死循环。不过只要不在立即扩张或者是执行中使用,就没有问题,使用了就出现死循环错误。
- 立即扩张中使用延迟变量,如果有延迟变量还没有设置,那么就会出现空值。
VAR=$(VAR)+1
等价于exp=maps.get(exp)
再递归从左往右解析又解析自身,不停的死循环。
-
-
指令变量和重载
-
多行变量
-
需要换行
- 默认情况下是没有换行的,多行也需要用
\\n
的方式连接,而且还会被转意为空格。 - 为了弥补这样的缺陷就通过指令
define
来定义真正意义的多行变量。
- 默认情况下是没有换行的,多行也需要用
-
多行变量
- 多行变量的语法不同。
- 但是定义的运算符都一样。
=,:=,::=,?=,+=,!=
。
-
用处
- 可以定义
recipe
,真正的多行指令,可以看成自定义的.ONESHELL
。 - 可以定义长变量,而不用每行末尾加
\
。 - 可以创建变量调用
eval
内置函数来动态生成rule
和变量定义。
- 可以定义
-
格式
define var
,名字可以包含函数变量引用等。- 先吃一个非空白字符,如果第一个是
+=,:=
这些运算符,则吃掉,按照对应类型解析,如果没有,默认使用=
.所以复制运算符是可选。 - 吃的第一个非空字符不是运算符,那么就是第一个值。直到一行仅仅包含
endef
位置。
-
案例
define varname asdfasdlfjsad asdfasjd asdfas = adfaksdfja endef
-
说明
- 复制运算符为可选,这种除了支持真正的多行外,其他的和普通的变量赋值一样。
- 这些都是值,即使里面有
#
开头的,也是值。 - 具体是什么用,根据其扩张后的位置有关。
- 这种也是支持
override
的,反正普通变量支持的这个都支持。 - 不支持的这个也支持。
-
-
取消定义
-
环境变量
-
规则特定值
-
默认
- 除了自变量意外的变量都是全局变量。
- 自变量属于局部变量。
-
自定义局部变量
- 复制应该单独的,
target
应该定义,所以如果要定义局部变量,最少要定义两条规则。 - 可以使用
export override private
这些局部的。 - 如何将
prerequisites
和变量定义混合呢?可以使用多次定义无recipe
的方式。 - 操作符可以是
=,:=,::=,+=,?=
. - 在
prereuiqistes
中定义仅仅是定义一个局部变量,和prerequisites
无关。 - 如果是多次定义也会按照局部处理逻辑来处理。规则也是一样的,也存在覆盖,递归扩张等。
- 如果是
-e
也会适用。
- 复制应该单独的,
-
案例
a.out: CFLAGS = -g a.out: a.cpp @gcc $(CFLAGS) $< -o $@
-
须知
-
案例
.PHONY:all always all:a.cpp b.cpp @echo all a.cpp:OK=a.cpp a.cpp: a.h a.out @echo a.cpp b.cpp:OK=b.cpp b.cpp: a.h b.out @echo b.cpp a.h:always; @echo a.h:$(OK) a.out b.out:; always:;
-
说明
a.h
被make
标记为最新了之后就不会再次执行。- 因为
make
一次只会执行一个target
一次。 - 所以
OK
的值和先后顺序有关。
-
额外
- 对于正则规则也可以使用类似的规则进行添加。
-
案例二
.PHONY:release debug release:CFLAGS=-o3 release:a.out @echo release debug:CFLAGS=-g debug:a.out @echo debug a.out:a.cpp @g++ $(CFLAGS) $@ -o $<
-
-
禁止传递
变量定义
最新推荐文章于 2023-03-02 22:04:03 发布