变量
- makefile 中支持程序设计语言中的变量的概念
- makefile 中的变量只代表文本数据(字符串)
- makefile 中的变量名规则:
- 变量名可以包含字符,数字,下划线
- 不能包含 “:”, “#”, “=”, 或 “ “
- 变量名大小写敏感
所以 makefile 中的变量不需要声明类型;
在 makefile 中使用变量前可以不去定义它,但是这样将会得到一个空值
变量的定义和使用
makefile 中变量的赋值方式
- 简单赋值(:=)
- 递归赋值(=)
- 条件赋值(?=)
- 追加赋值(+=)
:= 简单赋值
只对当前语句的变量有效
= 递归赋值
赋值可能影响多个其他变量
所有与目标变量相关的其他变量都将受到影响
?= 条件赋值
如果变量未定义,使用赋值符号中的值定义变量
如果变量已经定义,则赋值无效
+= 追加赋值
原变量值后加上一个新值
原变量值与新值之间由空格隔开
小结
makefile 中支持变量的定义和使用
makefile 中存在四种变量的赋值方式
- 简单赋值(:=)
- 递归赋值(=)
- 条件赋值(?=)
- 追加赋值(+=)
预定义变量
- 自动变量
- $@,$^,$<
- 特殊变量
- $(MAKE), $(MAKECMDGOALS), $(MAKEFILE_LIST)
- $(MAKE_VERSION),$(CURDIR),$(.VARIABLES)
- ……
自动变量
$@
- 当前规则中,触发命令被执行的目标(即当前规则中的目标);
$^
- 当前规则(目标)中的所有依赖
$<
- 当前规则中的第一个依赖
1 | # 示例 |
“$” 对于 makefile 有特殊含义,输出 “$” 时需要加上一个 “$” 进行转义;
“$@” 对于 Bash shell 有特殊的含义,输出时需要加上 “\“ 进行转义;
特殊变量
- $(MAKE)
- 当前 make 解释器的文件名
- $(MAKECMDGOALS)
- 命令行中指定的目标名(make 的命令行参数)
- $(MAKEFILE_LIST)
- make 所需要处理的 makefile 文件列表
- 当前 makefile 的文件名总是位于列表的最后
- 文件名之间以空格进行分隔
1 | # 示例 |
- $(MAKE_VERSION)
- 当前 make 解释器的版本
- $(CURDIR)
- 当前 make 解释器的工作目录
- $(.VARIABLES)
- 所有已经定义的变量名列表(预定义变量和自定义变量)
1 | # 示例 |
小结
- maekefile 提供了预定义变量供开发者使用
- 预定义变量的使用能够使得 makefile 的开发更高效
- 自动变量是 makefile 中最常见的元素
- 使用 $(.VSRLABLES) 能够获取所有的特殊变量
变量高级用法
变量值的替换
- 使用指定字符(串)替换变量值中的后缀字符(串)
- 语法格式:$(var:a=b) 或 ${var:a=b}
- 替换表达式中不能有任何的空格
- make 中支持使用${}对变量进行取值
1 | # 示例 |
变量的模式替换
- 使用 % 保留变量值中的指定字符,替换其他字符
- 语法格式:$(var:a%b=x%b) 或 ${var:a%b=x&b}
- 替换表达式中不能有任何的空格
- make 中支持使用${}对变量进行取值
1 | # 示例 |
规则中的模式替换
1 | # 示例 |
作用:通过 target-pattern 从 target 中匹配子目标;再通过 prereq-patern 从子目标生成依赖;进而构成完整的规则。
此处,%.o 从 OBJS 中匹配以 .o 结尾的文件,这是就先找到了 func.o 这个文件名;%.o : %.c 表示对于每一个 .o 文件他都依赖于一个同名的 .c 文件(即文件名除了扩展名外完全相同,);基于以上规则第一个
func.o : func.c
gcc -o $@ -c $^
就被构建出来了,main.o 也是同理。
变量值的嵌套引用
- 一个变量名之中可以包含对其它变量的引用
- 嵌套引用的本质是使用一个变量表示另外一个变量
命令行变量
- 运行 make 时可以在命令行定义变量,命令行中输入的默认覆盖 makefile 中定义的变量
1 | # 示例 |
在实际开发中,可用于零时改变某个变量的值,以得到一个特殊的可执行编译程序(测试程序)
override 关键字
- 用于指示 makefile 中定义的变量不能被覆盖
- 变量的定义和赋值都需要使用 override 关键字
1 | # 示例 |
override 关键字仅对后续在 Makefile 中定义的变量生效,如果在 Makefile 中先定义了变量,然后在其后使用 override 关键字尝试覆盖它,那么这个 override 指令将不会有任何效果;
在 Makefile 中,即使一个变量被 override 修饰,它仍然可以在 Makefile 的后续部分进行二次赋值;
override 主要影响的是命令行参数(通过 make VAR=value 传递的)和通过 -e 选项传递给 make 的环境变量,让其不可被覆盖命令行变量覆盖;
define 关键字
- 用于在 makefile 中定义多行变量
- 多行变量的定义从变量名开始到 endef 结束
- 可使用 override 关键字防止变量被覆盖
- define 定义的变量等价于使用 = 定义的变量
1 | # 示例 |
环境变量(全局变量)
也是操作系统中的环境变量
- makefile 中能够直接使用操作系统中的环境变量
- 当定义的变量与系统环境变量同名时,环境变量将被覆盖
- 运行 make 时指定 “-e” 选项,优先使用环境变量
为什么要在 makefile 中使用环境变量?
- 优势
- 环境变量可以在所有 makefile 中使用
- 劣势
- 过多的依赖于环境变量会导致移植性变差
变量在不同 makefile 之间的传递方式
- 直接使用外部定义的环境变量(操作系统的环境变量)进行传递
- 存在操作系统之间移植性的问题
- 使用 export 定义变量进行传递(定义临时环境变量)
- 因为变量都是在各自 makefile 文件中进行定义,所以不存在移植性的问题
- 定义 make 命令行变量进行传递(推荐)
1 | # 示例1 |
此处 makefile.2 中输出的 JAVA_HOME 为何还是 makefile.1 中的值呢?
因为 JAVA_HOME 为系统的环境变量,当我们子啊 makefile.1 中改写了 JAVA_HOME 之后,它的生命周期在整个 make 环境中都是有效的;
为什么在 makefile.2 中 var 是无效的呢?
因为 var 是在 makefile.1 中定义的变量,他的生命周期或者说作用域只在 makefile.1 这个文件中有效;
1 | # 示例 |
使用 export 定义的变量可以进行传递,这个变量将在该 makefile 及其所有通过它直接或间接调用(如使用 -f 参数指定或通过 include 指令包含)的子 makefile 中可用;
使用命令行也可以将变量进行传递,作用域和 exprot 类似;
目标变量(局部变量)
- 作用域只在指定目标及连带规则中
- target : name
value - target : override name
value
- target : name
1 | # 示例 |
模式变量
- 模式变量是目标变量的扩展
- 作用域只在符合模式的目标及连带规则中
- target : name
value - target : override name
value
- target : name
1 | # 示例 |
小结
- 全局变量:makefile 外部定义的环境变量
- 文件变量:makefile 中定义的变量
- 局部变量:制定目标的变量