Makefile中的eval

本文深入探讨Makefile中的eval与call函数的用法,通过实例解释如何使用这两个函数来解析和执行多行变量,特别关注在OpenWrt编译环境中如何应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里将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。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值