变量
-
定义变量
- 变量名 = 变量值
-
引用变量
- $(变量名)或${变量名}
-
变量名规则:
- 可以以数字开头
- 大小写敏感
-
除了用户自定义变量,makefile也提供了一些变量,例如:
- CC:gcc编译器
- CPPFLAGS:c预处理的选项
- CFLAGS:c编译器的选项
- LDFLAGS:链接器的选项
-
自动变量(只能在规则中的命令中使用)
- $@:表示规则中的目标
- $<:表示规则中的第一个条件
- $^:表示规则中的所有条件,组成一个列表,以空格隔开,并且消除重复项
- $*:匹配通配符%的部分,例如规则中的%.c匹配了foo.c,则$*的值为foo
- $?:比目标文件更新的所有依赖文件名称列表
-
模式规则
-
例如%.o %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
-
-
一些特殊变量
- $(MAKE):用于递归调用makefile的命令,一般情况下被设置为make
- $(MAKECMDGOALS):被执行的makefile的目标列表
- $(CURDIR):当前工作目录的完整路径
- $(RM):用于删除文件的命令,默认是rm -f
- $(AR):用于创建静态库的命令,默认是ar
- $(ARFLAGS):传递给$(AR)命令的选项,默认为空
条件判断
ifeq和ifneq分别表示等于和不等于的条件判断语句。ifdef和ifndef用于判断变量是否被定义
ifeq ($(val), value)
...
else
...
endif
条件判断语句必须以tab键开头,并以endif结尾。在使用条件判断语句时,可能会遇到空格的情况,可以用$(strip)函数来去除变量值两端的空格。在条件判断语句中,可以使用多行语句来表示不同的命令。在条件判断语句中可以对变量进行赋值,但是在定义变量时,需要使用:=进行赋值。
Makefile 语言是分为读取阶段和解释执行阶段的。在读取阶段,Makefile 会将 Makefile 中所有的变量和规则读取进来,同时对所有的预处理命令进行处理,包括条件判断语句。在解释执行阶段,Makefile 会根据具体的规则执行相关的命令。
因此,条件判断语句只在 Makefile 文件读取阶段有用,在解释执行阶段并不会生效。换句话说,条件判断语句的作用是决定 Makefile 文件中哪些规则会被解释执行,哪些规则不会被执行。
需要注意的是,在 Makefile 文件读取阶段,Makefile 会对条件判断语句进行预处理,并根据条件判断语句的结果生成不同的 Makefile 文件。因此,如果在条件判断语句中使用了动态变量或者命令,它们的值并不会被保留到解释执行阶段。如果想要在解释执行阶段获取变量或命令的值,需要在条件判断语句中将它们保存到变量中,并在后续的解释执行阶段中使用这些变量。
函数
- wildcard:查找指定目录下的指定类型的文件src = $(wildcard *.c)
- patsubst:匹配替换 objs = $(patsubst %.c, %.o, $(SRC))把SRC变量中所有有后缀的.c文件替换成.o
赋值
-
“=” 是最普通的等号,使用“=”进行赋值的时候,变量的值是整个makefile最后被指定的值
VIR_A = A VIR_B = $(VIR_A)B VIR_A = AA
所以VIR_B的值是AAB
-
“:=“表示直接赋值,赋予当前位置的值
VIR_A := A VIR_B := $(VIR_A)B VIR_A := AA
VIR_B的值为AB
-
“?=“表示如果该变量没有被赋值,则赋予等号后面的值,一般用于给定初始化默认值
VIR := OLD VIR ?= NEW
这里VIR的值最终就是OLD
-
“+=”表示将等号后面的值添加到前面的变量上
伪目标
Makefile 伪目标是一类特殊的目标,它们的目的是提供给 make 工具一些命令,而不是用来构建文件的。因为伪目标通常不会对应实际的文件,所以它们的目的也不是为了构建文件,而是执行一些特定的操作,如清理编译过的目标文件、运行测试等。
Makefile 伪目标的名字通常没有实际的文件名或者函数名那么有意义,通常以 .PHONY 为名,表示该目标是伪目标,不对应实际的文件。
伪目标的意义在于:
- 对常用的操作或任务进行命名约定
- 避免与同名文件冲突
- 组织和管理构建任务
- 提高可读性和可维护性
- 执行常用操作
技巧
- 在命令前加上@可以不显示出执行的命令
- 在执行make时,make会根据规则的依赖关系判断哪些规则需要重新执行以及哪些规则可以跳过(如果目标的依赖文件没有更新,那么旧没有必要重新生成目标文件,因此会跳过这条规则)