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. CentOS7 从管理员组中 新增/删除用户

    $ sudo usermod -aG wheel usera #增加 $ sudo usermod -G usera usera # 删除

  2. MySQL错误ERROR 2002 (HY000): Can't connect to local MySQL server

    From: http://www.jb51.net/article/56952.htm 这篇文章主要介绍了MySQL错误ERROR 2002 (HY000): Can't connect to loc ...

  3. Mybatis最入门---数据库的下载与安装

    [一步是咫尺,一步即天涯] 近期.因为工作进度调整,之前的Spring教程就先临时告一段落了,兴许找个时间继续更新,假设有那位看官想了解某个内容的,敬请留言,大家一起学习. 作为数据库工具的使用开篇. ...

  4. tablediff工具实用

    1. tablediff 是什么? tablediff 实用工具用于比较两个非收敛的表中的数据,它对于排除复制拓扑中的非收敛故障非常有用. 2. tablediff 用哪些用法? 1) . 在充当复制 ...

  5. Xcode密钥没有备份或者证书过期,出现Valid Signing错误

    密钥没有备份 或者证书过期,和Xcode 4.4中的证书,出现  Valid Signing 错误时   1.生成私有证书,打开钥匙串,钥匙串访问 – 证书助理 – 从证书颁发机构请求证书…,填入iD ...

  6. gtest运行小析

    Gtest是google推出的C++测试框架,本篇文档,从整体上对Gtest的运行过程中的关键路径进行分析和梳理. 分析入口 新建一个最简单的测试工程,取名为source_analyse_proj,建 ...

  7. git push 不再需要重复输入账户密码的技巧

    添加用户环境变量 计算机—属性—高级系统设置—环境变量 变量名 HOME 变量值%USERPROFILE% 在用户文件夹C:\Users\YourName下新建一个名为_netrc的文件 machin ...

  8. TensorFlow安装,升级,基本操作

    一. 安装 ubuntu 16 python 2.7 pip install tensorflow 测试安装完成效果: 查看tensorFlow版本python import tensorflow a ...

  9. Dos命令大全(1)

    MS DOS 命令大全 一.基础命令 1 dir 无参数:查看当前所在目录的文件和文件夹. /s:查看当前目录已经其所有子目录的文件和文件夹. /a:查看包括隐含文件的所有文件. /ah:只显示出隐含 ...

  10. kendo-ui下拉树形选择(DropDownTreeView)

    摘要: 最近项目中有一个特殊的需求,下拉选择部门,但是部门的层级关系要在下来框中体现出来,如下图 下面我就把实现的过程分享给大家,代码如下: dropdowntreeview.js /* * * Dr ...