makefile中的函数包括预定义函数,如wildcard、subst等,除此之外,我们还可以像c语言那样自定义函数以便于我们使用。
目录
一、函数定义 —— define … endef
自定义函数一般是
命令的集合
,搭配不同的函数可以定义不同的内容。函数使用的符号是 define。语法格式如下:
define 函数名
...
endef
示例:定义一个myFunc函数
define myFunc
@echo "func name is $(0)\n"
@echo "first param is $(1)\n"
@echo "second param is $(2)\n"
endef
-
$(0):表示函数名
-
$(1):表示传给函数的第一个参数
-
$(2):表示传给函数的第二个参数
二、call 函数
1、call 函数格式
call 函数能够 给自定义函数传递参数,并展开。 call 调用自定义函数的步骤是
-
先给自定义函数传参(如果有的话)
-
在call调用的位置直接展开自定义函数
调用格式如下。
$(call 函数名 参数1, 参数2, ...)
注意:
一般而言,call 本身并不具备编译功能,
call 只是将自定义函数在当前位置展开
,遇到
Makefile内置函数会自动执行
(比如 info,warning等)
2、call 函数展开过程分析
我们可以使用 info 函数打印一下 call 展开自定义函数以后的结果。我们要测试如下几点是否会被展开,即是否会展开 $()
- 自定义变量:$(BUILD_DIR)
- 函数:$(info hello world)
- 预置变量:$@
# 无论你把函数定义或者调用放在哪
# Makefile 在编译的时候,一定会把目标对象的生成放到最后。
all:
# 自定义变量
BUILD_DIR = build
# 自定义函数foo
define foo
$(info hello world)
$$(info hello world)
echo $(BUILD_DIR)
ps jax | grep tcp
target:main.c
gcc -o $@ $^
endef
###############################################
# 打印 call 展开自定义函数的内容
$(info $(call foo))
$(info hello world)
:去掉 $,变成 info hello world,函数自动执行,打印结果是 hello world
$$(info hello world):
去掉一层 $,展开结果是 $(info hello world)
echo $(BUILD_DIR)
:变量被展开(去掉 $), 展开的结果是echo build
ps jax | grep tcp
:无需展开
target: main.c
:无需展开
gcc -o $@ $^
:
$@ 被展开
(去掉 $),
因为call 只是展开,他也不知道 $@ 代表啥,展开结果为空
###############################################
# 打印 call 展开自定义函数的内容
$(info \
hello world
$(info hello world)
echo build
ps jax | grep tcp
target: main.c
gcc -o
)
三、eval 函数
1、eval 函数格式
eval 可以将 <text> 中的内容作为makefile的一部分,然后按照makefile的语法解析这些内容,无返回值。该函数在执行时会对参数
展开两次
,可以理解为第一次是eval函数检查<text>语法,第二次是解析并执行 <text>内容。
$(eval <text>)
2、eval 函数展开过程分析
因为每展开一次会去掉一层 $,因此有些地方需要加两层 $
# echo $$(BUILD_DIR) 展开以后eval无法解析
# ps jax | grep tcp 展开以后eval无法解析
# 自定义变量
BUILD_DIR = build
define foo
$(info $(BUILD_DIR))
$(info $$(BUILD_DIR))
$$(info $$(BUILD_DIR))
target:main.c
gcc -o $$@ $$^
endef
$(eval $(call foo))
第一次展开
$(info $(BUILD_DIR))
:去掉一层 $ 变成 info build,直接执行info函数,打印 build
$(info $$(BUILD_DIR))
:去掉一层 $ 变成 info $(BUILD_DIR),直接执行info函数,打印 $(BUILD_DIR)
$$(info $$(BUILD_DIR))
:去掉一层 $ 以后变成了 $(info $(BUILD_DIR)),此时的info 函数无法执行,继续下一行。
target:main.c
:不做任何处理,无需展开,继续下一行
gcc -o $$@ $$^
:去掉一层 $ 变成 gcc -o $@ $^
# build
# $(BUILD_DIR)
$(info $(BUILD_DIR))
target:main.c
gcc -o $@ $^
第二次展开
第一次展开以后,注释部分表示打印到控制台,剩下的就是待解析的部分。剩余部分交由Makefile解析,得到的结果就是
# build
# $(BUILD_DIR)
build
gcc -o target main.c