Android.mk的使用方法

在上一篇Android编译系统入门(一)中我们只要介绍了Android系统使用make命令默认编译的依赖树是droid,而droid是一个伪目标,它有两个先决条件droidcore和dist_files,其中重点是droidcore,它主要用于编译系统所需的system.img,boot.img等。有了上一篇的基础,今天我们要分析一下Android.mk文件在整个编译系统中的地位和作用。

一棵大树的繁茂和枝叶的多少息息相关。一方面只有枝干足够茁壮才能托起枝叶,另一方面枝叶的光合作用也能促进枝干的生长。那么在Android编译系统中,droid就是这棵树中强有里的枝干,而Android.mk则是一片片的叶子,纵观整个Android平台Android.mk的数量在一千个以上。那么如此多的makefile文件又是在何时被整合进整个编译系统的呢?其实答案还是在main.mk中。

ifneq ($(ONE_SHOT_MAKEFILE),)
# We've probably been invoked by the "mm" shell function
# with a subdirectory's makefile.
include $(ONE_SHOT_MAKEFILE)
# Change CUSTOM_MODULES to include only modules that were
# defined by this makefile; this will install all of those
# modules as a side-effect. Do this after including ONE_SHOT_MAKEFILE
# so that the modules will be installed in the same place they
# would have been with a normal make.
CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS)))
FULL_BUILD :=
# Stub out the notice targets, which probably aren't defined
# when using ONE_SHOT_MAKEFILE.
NOTICE-HOST-%: ;
NOTICE-TARGET-%: ; # A helper goal printing out install paths
.PHONY: GET-INSTALL-PATH
GET-INSTALL-PATH:
@$(foreach m, $(ALL_MODULES), $(if $(ALL_MODULES.$(m).INSTALLED), \
echo 'INSTALL-PATH: $(m) $(ALL_MODULES.$(m).INSTALLED)';)) else # ONE_SHOT_MAKEFILE ifneq ($(dont_bother),true)
#
# Include all of the makefiles in the system
# # Can't use first-makefiles-under here because
# --mindepth=2 makes the prunes not work.
subdir_makefiles := \
$(shell build/tools/findleaves.py $(FIND_LEAVES_EXCLUDES) $(subdirs) Android.mk) $(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk))) endif # dont_bother

ONE_SHOT_MAKEFILE变量和编译选项有关,当选择默认make命令进行整编的时候ONE_SHOT_MAKEFILE值为空,这是就会走下面这个分支

subdir_makefiles := \
$(shell build/tools/findleaves.py $(FIND_LEAVES_EXCLUDES) $(subdirs) Android.mk) $(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))

其中就是通过findleaves.py这个脚本来查找所有的Android.mk文件但可能并不是所有的Android.mk都会被包好进来比如.repo .git下的就会被排除在外。这些排除选项由FIND_LEAVES_EXCLUDES决定。所有被包含进来的Android.mk的路径都会被追加到subdir_makefiles变量,接着通过一个foreach函数将所有的Android.mk文件都include进来。其中$(info including $(mk) ...)负责打印这些文件信息,如下



再通过eval函数执行include操作将Android.mk文件整合进整棵大树。

OK,到这里所有的Android.mk文件都被包含进来了,等整个大树被构建完成后make会从依赖树最外层的叶子开始往上执行所有的COMMANDS。

接下来我们选取Settings模块作为例子,详细的解释一下Android.mk的编写规则和一些注意事项。Settings模块的Android.mk内容如下

#LOCAL_PATH表示当前目录的地址,一般位于include $(CLEAR_VARS)之前
LOCAL_PATH:= $(call my-dir) #CLEAR_VARS对应的是clean_vars.mk,用于清除除了LOCAL_PATH以外的所有LOCAL_打头的变量
include $(CLEAR_VARS) #重定向java库文件
LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt telephony-common ims-common #重定向java静态库文件
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v13 jsr305 #模块tag为optional,表示不管是选择了什么模式都会编译该模块
LOCAL_MODULE_TAGS := optional #重定向本地源码
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
src/com/android/settings/EventLogTags.logtags #重定向本地资源文件
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res #模块名
LOCAL_PACKAGE_NAME := Settings #模块证书签名
LOCAL_CERTIFICATE := platform #是否是特权文件
LOCAL_PRIVILEGED_MODULE := true #使用代码混淆
LOCAL_PROGUARD_FLAG_FILES := proguard.flags #判断是否进行增量编译
ifneq ($(INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JACK_ENABLED := incremental
endif #include三个makefile文件,进项相关变量赋值
include frameworks/opt/setupwizard/navigationbar/common.mk
include frameworks/opt/setupwizard/library/common.mk
include frameworks/base/packages/SettingsLib/common.mk #开始编译Settings模块,对应package.mk文件。感兴趣的可以进一步研究apk是怎么被编译出来的,里面还是很复杂的
include $(BUILD_PACKAGE) # 如果使用的是mm或mmm命令单编Settings模块的话会额外include test目录下的Android.mk,用于编译测试模块。
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call all-makefiles-under,$(LOCAL_PATH))
endif

通过上述对Android.mk文件的分析,我们可以看到需要编译一个模块要做的工作还是很少的,只要指定几个变量就可以了,这也得益与google的用心良苦,它把所有的公共操作都抽取了出来,做好了各种模板,如BUILD_PACKAGE等,我们要做的只是调用适当的模板就行了。

下面介绍一些Android.mk中常用的变量,以供读者参考。

变量名 说明
LOCAL_PATH 用于确定源码所在的目录,一般把它放在CLEAR_VARS变量引用的前面,因为它不会背清除,每个Android.mk只需要定义一次就行
CLAER_VARS 清空很多LOCAL_开头的变量(LOCAL_PATH除外)。因为所有的Makefile都是在一个编译环境下执行,因此变量的定义理论上都是全局的,每个模块开始编译前进行清理工作是必不可少的
LOCAL_MODULE 模块名,需要保证唯一存在且中间不能又空格
LOCAL_MODULE_PATH 模块的输出路径
LOCAL_SRC_FILES 模块编译所涉及的源文件。如果是java程序,可以考虑调用all-java-files-under添加java代码。因为有LOCAL_PATH,所以这里只需要给出文件名即可,如src
LOCAL_CC 用于指定C编译器
LOCAL_CXX 用于指定C++编译器
LOCAL_CPP_EXTENSION 用于指定特殊的C++文件后缀名
LOCAL_CFLAGS C语言编译时的额外选项
LOCAL_CXXFLOAGS C++编译时的额外选项
LOCAL_C_INCLUDES 编译C和C++时需要的额外头文件
LOCAL_STATIC_LIBRARIES 编译所需的静态库列表
LOCAL_SHARED_LIBRARIES 编译所需的共享库列表
LOCAL_JAVA_LIBRARIES 编译时所需的JAVA类库
LOCAL_LDLIBS 编译时所需的链接选项
LOCAL_COPY_HEADERS 安装应用程序时需要复制的头文件列表,需要和LOCAL_COPY_HEADERS_TO变量配合使用
LOCAL_COPY_HEADERS_TO 上述头文件列表的复制目的地
BUILD_XX_XX 各种形式的编译模板,如生成静态、动态库文件,可执行文件,文档等

总结

在Android编译系统的学习中,我们先从最基础的makefile语法规则入手,导出了依赖树的概念,然后按照依赖树的结构逐步梳理出一个完整的Android版本编译所设计的几个重要节点。Android编译系统是非常庞大的,不过经过这次的学习希望大家能够对它的结构和基本原理有一个初步的认识。那么接下来的各种编译细节也能通过代码的研读和分析变得明朗起来。

Android编译系统入门(二)的更多相关文章

  1. Android编译系统入门(一)

    做过Android平台开发的朋友对make,mm或make clean命令应该很熟悉,但也许大家只是熟知这些命令的作用却不知道这些命令底下有些什么原理?那么今天我就带着大家推开Android编译系统的 ...

  2. Android工程师入门(二)——不忙不累怎么睡。。

    安卓开发迫在眉睫,这周入个门吧! Android工程师入门(二) 四.在界面中显示图片 ImageView 是显示图片的一个控件. --属性 src——内容图片: background——背景图片/背 ...

  3. Bmob移动后端云服务平台--Android从零開始--(二)android高速入门

    Bmob移动后端云服务平台--Android从零開始--(二)android高速入门 上一篇博文我们简介何为Bmob移动后端服务平台,以及其相关功能和优势. 本文将利用Bmob高速实现简单样例,进一步 ...

  4. 深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)

    第四章.Android编译系统与定制Android平台系统 4.1Android编译系统 Android的源码由几十万个文件构成,这些文件之间有的相互依赖,有的又相互独立,它们按功能或类型又被放到不同 ...

  5. 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示

    前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...

  6. Android实现入门界面布局

    Android实现入门界面布局 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 代码实现 首先是常量的定义,安卓中固定字符串应该定义在常量中. stri ...

  7. Android编译系统详解(一)

    ++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: http://blog.csdn.net/mr_raptor/art ...

  8. 教我徒弟Android开发入门(一)

    前言: 这个系列的教程是为我徒弟准备的,也适合还不懂java但是想学android开发的小白们~ 本系列是在Android Studio的环境下运行,默认大家的开发环境都是配置好了的 没有配置好的同学 ...

  9. IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

    1.系列文章引言 1.1 适合谁来阅读? 本系列文章尽量使用最浅显易懂的文字.图片来组织内容,力求通信技术零基础的人群也能看懂.但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获.如果您大 ...

随机推荐

  1. 微软BI 之SSIS 系列 - 在 SSIS 中使用 Web Service 以及 XML 解析

    开篇介绍 Web Service 的用途非常广几乎无处不在,像各大门户网站上的天气预报使用到的第三方 Web Service API,像手机客户端和服务器端的交互等都可以通过事先设计好的 Web Se ...

  2. Atitit 视图参数解决方案 oracle版和mysql版本 attilax总结.docx

    Atitit 视图参数解决方案 oracle版和mysql版本 attilax总结.docx 1.1. Package机制1 1.2. 全局变量机制1 1.3. 临时表模式,oracle mysql都 ...

  3. Fluent动网格【7】:网格节点运动

    在动网格中,对于那些既包含了运动也包含了变形的区域,可以通过UDF来指定区域中每一个节点的位置.这给了用户最大的自由度来指定网格的运动.在其他的动网格技术中(如重叠网格)则很难做到这一点.定义网格节点 ...

  4. postman参数获取不到原因

    在使用postman时,会发现经常提示参数错误,然而代码没有问题,仔细一看,原来是粘贴复制参数到postman时,前后有空格.

  5. [firefox] Scrapbook Plus的改进版Scrapbook X

    我在两年前的博文<Firefox上一些我用于知识管理的扩展> 里面提到过我在用Scrapbook Plus这个Firefox扩展, 用它来撷取网页构建自己的知识库(可以加标注.可以搜索.可 ...

  6. 假设分配给命令的连接位于本地挂起事务中,ExecuteReader 要求命令拥有事务。命令的 Transaction 属性尚未初始化

    {System.InvalidOperationException: 假设分配给命令的连接位于本地挂起事务中.ExecuteReader 要求命令拥有事务.命令的 Transaction 属性尚未初始 ...

  7. 【iCore4 双核心板_ARM】例程一:ARM驱动三色LED

    实验原理: 通过STM32的三个GPIO驱动一个三色LED,引脚PB2接红色LED(ARM_LEDR), 引脚PA9接蓝色LED(ARM_LEDB),引脚PA10接绿色LED(ARM_LEDG),   ...

  8. 【6集iCore3_ADP触摸屏驱动讲解视频】6-2 基于FSMC总线的ARM与FPGA通信

    视频简介: 该视频介绍基于FSMC总线的ARM与FPGA通信   源视频包下载地址: 链接:http://pan.baidu.com/s/1slJDoQD 密码:tmw7   银杏科技优酷视频发布区: ...

  9. .Net MVC Cache 缓存技术总结

    一.细说 ASP.NET Cache 及其高级用法 二..Net环境下的缓存技术介绍 (转) 三.asp.net中缓存的使用介绍一 四.HttpContext.Current.Cache 过期时间

  10. 三、主流区块链技术特点及Hyperledger Fabric V1.0版本特点

    一.Hyperledger fabric V1.0 架构 1.逻辑架构: 2.区块链网络 3.运行时架构 二.架构总结 1.架构要点 分拆Peer的功能,将Blockchain的数据维护和共识服务进行 ...