我们也说说Android.mk(3) - 宏

来源:互联网 发布:域名邮箱怎么做 编辑:程序博客网 时间:2024/05/02 22:51

我们也说说Android.mk(3) - 宏

传统上我们一直称这种东西为makefile中的变量,其实本质上就是一个宏,只是做的是字符串替换。我们何如就把它叫做宏呢。

宏的命名

makefile的宏可以包含字符、数字、下划线。需要注意的一点是,宏就是宏,反正是要做字符串替换的,所以名字以数字开头是没问题的。makefile本身也不是用于数值处理的,以字符串为主。

使用一个宏的时候需要使用使shell$。
从中可以看到,我们前面学到的函数,其实本质上也就是宏,只不过是带有了参数的宏。

宏的赋值

= 和 :=

宏可以用其他宏的值来定义自己。最强大的是用=运算符。makefile是定义式的语言,不是按顺序一条一条执行的,所以,可以使用在这一行还没有定义的宏来为当前宏赋值,反正就是个宏展开么。

但是,这样如果造成的循环引用,就会引发意想不到的错误。在这种情况下,使用:=运算符,它是只允许引用在它之前定义的变量的。

?=

如果不知道定义没定义,可以使用?=来赋值,如果未定义,则定义。如果已经定义了,就什么也不做。

+=

如果之前未定义,则相当于=。如果之前有:=定义,则将新值按:=的规则添加到原值后面。

对宏进行比较

有4个关键字用于对宏的比较:
* ifeq:判断相等
* ifneq:判断不相等
* ifdef:判断非空,相当于ifneq(<参数>,)
* ifndef:如果为空,相当于ifeq(<参数>,)

例:

.PHONY : all7ifeq ($(DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := defaultendifall7 :    @echo $(DEX2OAT_HOST_INSTRUCTION_SET_FEATURES)

输出:

$ make all7default

请注意,ifeq, else, endif这些语句之前不能有Tab。

上面的例子是从Android.oat.mk中改造的。其实,跟下面的是等价的:

ifndef DEX2OAT_HOST_INSTRUCTION_SET_FEATURESDEX2OAT_HOST_INSTRUCTION_SET_FEATURES := defaultendif

定义多行的宏

可以通过使用define / endef来定义多行的大宏。

我们看一个例子:

 # $(1): compiler - default, optimizing, jit or interpreter. # $(2): wrapper. # $(3): dex2oat suffix.define create-core-oat-host-rule-combination  $(call create-core-oat-host-rules,$(1),no-pic,,$(2),$(3))  $(call create-core-oat-host-rules,$(1),pic,,$(2),$(3))  ifneq ($(HOST_PREFER_32_BIT),true)    $(call create-core-oat-host-rules,$(1),no-pic,2ND_,$(2),$(3))    $(call create-core-oat-host-rules,$(1),pic,2ND_,$(2),$(3))  endifendef

这个宏其实是个函数了。

eval函数

eval函数用于在宏定义或者是分支、循环结构中使用其他makefile语句时。

我们看一个在foreach中使用eval的例子:

$(foreach m,$(ALL_MODULES), \  $(eval r := $(ALL_MODULES.$(m).REQUIRED)) \  $(if $(r), \    $(eval r := $(call module-installed-files,$(r))) \    $(eval t_m := $(filter $(TARGET_OUT_ROOT)/%, $(ALL_MODULES.$(m).INSTALLED))) \    $(eval h_m := $(filter $(HOST_OUT_ROOT)/%, $(ALL_MODULES.$(m).INSTALLED))) \    $(eval t_r := $(filter $(TARGET_OUT_ROOT)/%, $(r))) \    $(eval h_r := $(filter $(HOST_OUT_ROOT)/%, $(r))) \    $(eval t_m := $(filter-out $(t_r), $(t_m))) \    $(eval h_m := $(filter-out $(h_r), $(h_m))) \    $(if $(t_m), $(eval $(call add-required-deps, $(t_m),$(t_r)))) \    $(if $(h_m), $(eval $(call add-required-deps, $(h_m),$(h_r)))) \   ) \ )

vpath宏

vpath宏用于指定makefile搜索源文件的目录,这个倒是有点变量的意思了

引用其他makefile

makefile基本上就是字符串替换,我们当然也可以通过include命令将一系列的其他makefile引用进当前的makefile.

例:

include art/build/Android.common_build.mk

自动宏

自动宏就是由make工具已经定义好的变量。

$@ 目标文件集

$@是指整个目标的文件集

例:

$(built_odex) : $(dir $(LOCAL_BUILT_MODULE))% : $(built_dex)    $(hide) mkdir -p $(dir $@) && rm -f $@    $(add-dex-to-package)    $(hide) mv $@ $@.input    $(call dexpreopt-one-file,$@.input,$@)    $(hide) rm $@.inputendif

$<

依赖的第一个文件名,可以和$@一起共用。

例:

$(built_odex) : $(my_prebuilt_src_file)    $(call dexpreopt-one-file,$<,$@)

调试与错误处理

输出消息

makefile的命令,默认都会输出出来。可以用@来隐藏显示。
通过echo命令,可以输出消息。一般都是用@echo,免得看见两次。

几条命令一起执行

如果这条命令用到上条命令的结果,需要在上条命令后面加分号

错误处理

如果makefile遇到命令出错,就会中止当前的依赖执行。可以通过在命令之前加上“-”来忽略错误。
我们也可以将忽略错误的目标以.IGNORE来声明。

如:

.IGNORE : all7
0 0
原创粉丝点击