这里将openwrt中编译ipk包的时候使用的的Makefile,进行简化拿来进行说明,主要用来实验eval函数的用法
PKG_NAME :=bcl_boot
define Package/$(PKG_NAME)
SECTION:=utils
CATEGORY:=Utilities
TITLE:=lziot_project
endef
define BuildPackage
$(eval $(Package/$(1)))
endef
#(1)
#$(Package/$(PKG_NAME))#error
#(2)
#$(call $(Package/$(PKG_NAME)))
#(3)
#$(call BuildPackage,$(PKG_NAME))# same as below two statements
#$(eval $(Package/$(PKG_NAME)))
#$(eval $(call Package/$(PKG_NAME)))
#(4)
#$(eval $(call BuildPackage,$(PKG_NAME)))#same as below statement
#$(eval $(eval $(call BuildPackage,$(PKG_NAME))))
test:
#$(eval $(call print, $(TITLE)))#error
$(call print, $(TITLE))
$(print)
print
@echo $(TITLE)
define print
@echo $(SECTION)
@echo $(CATEGORY)
@echo $(1)
endef
第3行定义了函数(也可以叫做多行变量)Package/bcl_boot,此函数中没有执行语句只有变量赋值,那么如果我们只是在以下Makefile中简单的调用call函数 来展开这些多行变量,(如果多行变量没有参数,可以不调用call函数,直接调用eval函数使其生效,既不调用call函数,也不调用eval函数将报错,如14行的调用方式)。
call函数的作用
call函数可以将多行变量展开,并将传入的参数替换掉多行变量中的$(1) $(2)等,可以参考上述9-11行BuildPackage函数的定义和20行函数的调用,但是call函数返回的仍然是Makefile中的文本语句,Makefile并未解析,这就引入了eval函数
eval函数的作用
eval函数可以将call函数返回的Makefile语句,或者直接将多行变量进行Make解析,使其生效,但是当多行变量中存在执行语句时,如35行print函数,禁止在调用print函数的地方使用eval函数(参见29行),但可以调用call函数进行变量替换,调用print的地方也只能在某个target 的有效范围内,因为Makefile中只有在这里才允许出现执行语句,因为此时必须是Makefile格式的纯文本信息,其他变量赋值信息在指定target目标执行前早已解析完毕,并且已经生效。
第9行定义了BuildPackage多行变量,它的作用主要是使 Package/$(PKG_NAME)多行变量被Makefile解析生效;
13-26行分别尝试了各种方式来调用eval和call来测试是否能使Package/$(PKG_NAME)生效,其中(1)会报错(以上已经有描述),(2)不报错,但是并不能使其生效,执行结果如下:
print
(3)(4)都可以使其生效,执行结果如下:
utils
Utilities
lziot_project
utils
Utilities
print
lziot_project
这里可以看出eval的嵌套调用并不会影响结果;
28-34行测试了test目标中调用print多行变量的方式,29行会报错(以上已经有描述),30行和31行都能正确执行,32行只是会单纯打印print,并无其他效果,执行结果见上
补充
其实自定义函数不一定是多行变量,也可以是单行的普通变量,如下:
CC := arm-linux-gnueabihf-gcc
cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
ccflags-y += $(call cc-option, -fno-toplevel-reorder,-v)
my_test:
@echo "ccflags-y"=$(ccflags-y)
这里cc-option就是一个普通变量,但是可以作为一个函数被call调用(第5行),摘自uboot的makefile中,此变量的作用是用来检查交叉编译器是否支持某些参数,这里用来检查-fno-toplevel-reorder参数是否被arm-linux-gnueabihf-gcc支持,如果支持就将此参数加入ccflags-y变量,如果不支持就将-v参数加入ccflags-y变量,这里只是用-v参数举例,运行结果如下:
sallenkey@sallenkey-virtual-machine:~$ make
ccflags-y= -fno-toplevel-reorder
证明arm-linux-gnueabihf-gcc支持参数-fno-toplevel-reorder。