https://www.jianshu.com/p/7c20b299ee63

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

宏的命名

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

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

宏的赋值

= 和 :=

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

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

?=

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

+=

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

对宏进行比较

有4个关键字用于对宏的比较:

  • ifeq:判断相等
  • ifneq:判断不相等
  • ifdef:判断非空,相当于ifneq(<参数>,)
  • ifndef:如果为空,相当于ifeq(<参数>,)

例:

.PHONY : all7
ifeq ($(DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)
DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
endif
all7 :
@echo $(DEX2OAT_HOST_INSTRUCTION_SET_FEATURES)

输出:

$ make all7
default

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

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

ifndef DEX2OAT_HOST_INSTRUCTION_SET_FEATURES
DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
endif

定义多行的宏

可以通过使用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))
endif
endef

这个宏其实是个函数了。

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 $@.input
endif

$<

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

例:

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

调试与错误处理

输出消息

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

几条命令一起执行

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

错误处理

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

如:

.IGNORE : all7

作者:Jtag特工
链接:https://www.jianshu.com/p/7c20b299ee63
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Android.mk(3) 宏的更多相关文章

  1. Android.mk 常用宏和变量

    android ndk开发有一个重要的文件 Android.mk,他虽然重要,但是对它进行深入介绍的文档却比较的少,这里将对Android.mk中常用的宏和变量进行说明: 由于这一部分的内容多,资料零 ...

  2. Android.mk中添加宏定义

    在Boardconfig.mk 中添加一个 IS_FLAG := true 由于Boardconfig.mk和各目录的Android.mk是相互关联的 所以我们可以在Android.mk 中添加 一个 ...

  3. Android.mk中添加宏定义【转】

    本文转载自:http://blog.csdn.net/huangyabin001/article/details/38302021 在Boardconfig.mk 中添加一个 IS_FLAG := t ...

  4. Android.mk宏定义demo【转】

    本文转载自:http://blog.csdn.net/u010164190/article/details/72783963 1.Android.mk  LOCAL_PATH := $(call my ...

  5. Android.mk 文件语法详解

    0. Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build Syst ...

  6. Android.mk 基本应用

    如果是在android源码里面编译我们自己的应用,就需要这个android.mk文件,这个文件就告诉android系统应用如何来编译这个应用以及这个应用它所依赖哪些文件等等信息.我对android.m ...

  7. android编译系统的makefile文件Android.mk写法

    Android.mk文件首先需要指定LOCAL_PATH变量,用于查找源文件.由于一般情况下Android.mk和需要编译的源文件在同一目录下,宏函数“my-dir”右编译系统提供的,用于返回当前路径 ...

  8. Android.mk相关知识

    Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握jni,就必须熟练掌握Andr ...

  9. Android.mk的用法和基础【转】

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

随机推荐

  1. C# Bitmap转化为BitmapImage方法

    public BitmapImage BitmapToBitmapImage(Bitmap bitmap) { Bitmap bitmapSource = new Bitmap(bitmap.Widt ...

  2. linux中iptables的用法

    iptables基本操作笔记 一.基本操作 #启动防火墙 service iptables start #停止防火墙 service iptables stop #重启防火墙 service ipta ...

  3. 通过tarball形式安装HBASE Cluster(CDH5.0.2)——重新编译CDH5.0.2 HADOOP点滴

    本文参考博文Hadoop2.2.0遇到64位操作系统平台报错,重新编译Hadoop 由于我采用的tarball方式安装hadoop,其lib/native下根本没有内容,启动hdfs时报这个经典的na ...

  4. spring mvc 框架URL接收中文参数的乱码解决方案

    后台可能就会出现乱码,具体解决方案如下: 一. 配置tomcat目录下的service.xml文件 tomcat7/conf/server.xml 给该行代码加上 URIEncoding=" ...

  5. jQuery实现自动调用和触发某个事件的方法

    1.比如我们通过jquery定义了一个点击事件,我们如何自动触发他: $(function(){    $('#button').click(function(){      alert('butto ...

  6. php下webservice使用总结

    基于thinkphp3.2的 1.修改php配置 php.ini extension=php_soap.dll soap.wsdl_cache_enabled=0 2.soap有两种模式 wsdl和 ...

  7. Centos修改时间显示的时区,将UTC修改为CST

    问题说明: 今天一同事反应,系统的时间不对和正常的时间差8个小时.就登录主机看了下时间 系统时间显示为: # date Fri Dec :: UTC # 备注:查看了下,正好和当前的时间差了8个小时. ...

  8. 【scala】 scala 条件控制 和异常处理(二)

    1.scala 变量定义 ,var val 区别. var 定义可变变量 val 定义不可变变量,scala 推荐使用.相当于Java的final 变量. scala中包含的基本数据类型详情如下表所示 ...

  9. iOS使用NSURLConnection发送同步和异步HTTP Request

    1. 同步发送 - (NSString *)sendRequestSync { // 初始化请求, 这里是变长的, 方便扩展 NSMutableURLRequest *request = [[NSMu ...

  10. Java实现在复制文件时使用进度条

    在对大文件操作时,可能会需要些时间,此时为用户提供进度条提示是非常常见的一项功能,这样用户就可以了解操作文件需要的时间信息.本实例为大家介绍了在复制大的文件时使用的进度条提示,需要注意的是,只有在读取 ...