Android编译系统入门(二)
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编译系统入门(二)的更多相关文章
- Android编译系统入门(一)
做过Android平台开发的朋友对make,mm或make clean命令应该很熟悉,但也许大家只是熟知这些命令的作用却不知道这些命令底下有些什么原理?那么今天我就带着大家推开Android编译系统的 ...
- Android工程师入门(二)——不忙不累怎么睡。。
安卓开发迫在眉睫,这周入个门吧! Android工程师入门(二) 四.在界面中显示图片 ImageView 是显示图片的一个控件. --属性 src——内容图片: background——背景图片/背 ...
- Bmob移动后端云服务平台--Android从零開始--(二)android高速入门
Bmob移动后端云服务平台--Android从零開始--(二)android高速入门 上一篇博文我们简介何为Bmob移动后端服务平台,以及其相关功能和优势. 本文将利用Bmob高速实现简单样例,进一步 ...
- 深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)
第四章.Android编译系统与定制Android平台系统 4.1Android编译系统 Android的源码由几十万个文件构成,这些文件之间有的相互依赖,有的又相互独立,它们按功能或类型又被放到不同 ...
- 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...
- Android实现入门界面布局
Android实现入门界面布局 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 代码实现 首先是常量的定义,安卓中固定字符串应该定义在常量中. stri ...
- Android编译系统详解(一)
++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: http://blog.csdn.net/mr_raptor/art ...
- 教我徒弟Android开发入门(一)
前言: 这个系列的教程是为我徒弟准备的,也适合还不懂java但是想学android开发的小白们~ 本系列是在Android Studio的环境下运行,默认大家的开发环境都是配置好了的 没有配置好的同学 ...
- IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)
1.系列文章引言 1.1 适合谁来阅读? 本系列文章尽量使用最浅显易懂的文字.图片来组织内容,力求通信技术零基础的人群也能看懂.但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获.如果您大 ...
随机推荐
- 前后分离模型之封装 Api 调用
Ajax 和异步处理 调用 API 访问数据采用的 Ajax 方式,这是一个异步过程,异步过程最基本的处理方式是事件或回调,其实这两种处理方式实现原理差不多,都需要在调用异步过程的时候传入一个在异步过 ...
- ASP.NET MVC ViewBag/ViewData/TempData区别
ViewBag/ViewData public dynamic ViewBag { get; } public ViewDataDictionary ViewData { get; set; } Vi ...
- MATLAB 统计数据并画出统计直方图
统计FilmTrust(0.5-4.0分).CiaoDVD(1-5分).MovieLens(1-5分) 等 rating 数据集分值的分布: 以 统计FilmTrust(0.5-4.0分) 为例: ...
- SSD卡对redis的影响
原文地址:http://antirez.com/news/52 Hello! As promised today I did some SSD testing. The setup: a Linux ...
- Centos下Yum安装PHP 5.5、5.6、7.0
Centos系统自带的php版本很低,如果我们需要使用高版本的php,可以不用编译安装,直接用yum安装会非常省时省力. 1.检查当前安装的PHP包yum list installed | grep ...
- Atitit 医学之道 attilax总结
Atitit 医学之道 attilax总结 1. 相关的学科3 1.1. 口腔医学 ok3 1.2. 人体解剖学 ok3 1.3. 生理学 ok3 1.4. 病理学 ok3 1.5. 骨伤科学 ...
- 不同局域网中同一IP地址的计算机怎么通信的
1.IP地址在192.--.255之内的是私有地址,即192.168.1.56的电脑a是不能直接与192.168.1.56的电脑b进行通信的.他们需要用到NAT技术,即网络地址转换.2.NAT的作用是 ...
- 图灵数学·统计学丛书.PDF(53本全)
图灵数学·统计学丛书01-概率论及其应用(第1卷·第3版)-[美]William.Feller-人民邮电出版社.pdf 图灵数学·统计学丛书01-金融数学:衍生产品定价引论-[英]M·巴克斯特& ...
- 【Android】Android布局文件的一些属性值
第一类:属性值 true或者 false android:layout_centerHrizontal 水平居中 android:layout_centerVertical 垂直居中 androi ...
- 重定向如何携带cookie
起因 最近在做微信开放平台,需要给第三方入住,而且入住方都有自己的二级域名.做过微信开发的人都知道,坑爹的是微信并不支持这种二级域名的方式,所以用一个域名专门来处理. 问题 然后由于采用了一个专门的域 ...