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 适合谁来阅读? 本系列文章尽量使用最浅显易懂的文字.图片来组织内容,力求通信技术零基础的人群也能看懂.但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获.如果您大 ...
随机推荐
- CMD递归文件夹
SET dir=%~dp0 SET /a cnt=0 echo dir is: %dir% cd /d %dir% for /R %dir% %%i in (*.apk) do ( set /a cn ...
- 11G新特性 -- 块介质恢复性能增强(block media recovery)
块介质恢复性能增强(block media recovery) :只是恢复受损的块.不需要将受损的数据文件offline.针对受损的数据块,使用备份中好的数据块进行restore和recover,避免 ...
- 在代码中设置RelativeLayout布局中标签的android:layout_toLeftOf、android:layout_toRightOf等属性
需要动态改变RelativeLayout里面控件的相对位置,经一个技术群的群友提示,找到了如下的方法,做下记录: RelativeLayout.Layoutparams params = (Rel ...
- VSCode配置TypeScript
网上教程一堆,记录下我认为的关键点: 1.创建tsconfig.json,使用命令行在项目文件夹下输入“tsc --init”即可: 2.创建tasks.json,在VSCode中,使用ctrl+sh ...
- Clustered Shading架构实现步骤
最终决定越过Forward+,一步到位,直接调整至更先进的Clustered架构.步骤如下: 里程碑1:以CPU方式实现Light Culling,旨在理念验证,并与D3D10兼容里程碑2:以GPU ...
- django DateTimeField 时间格式化
['%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' '%Y-%m-%d %H:%M', # '2006-10-25 14:30' '%Y-%m-%d', # ' ...
- Hadoop 2.x 安装常见问题FAQ(一) NodeManager 无法启动问题解决
一.问题描述 在搭建 Hadoop hadoop-2.4.1 集群的最后一步启动集群,在命令窗口并没有报任何错误,但是Slave 节点的 NodeManager进程始终启动不起来.随后查看了后台启动日 ...
- MVC的Membership
摘自:http://stackoverflow.com/a/16734651/1616023 See the summaries below each quote for a quick answer ...
- Android Wifi 主动扫描 被动扫描
介绍主动扫描,被动扫描以及连接的wifi的扫描过程 参考文档 <802.11无线网络权威指南> <80_Y0513_1_QCA_WCN36X0_SOFTWARE_ARCHITECTU ...
- docker开源仓库Harbor部署笔记
Harbor介绍Harbor是Vmvare团队开发的开源企业级registry仓库,相比docker官方拥有更丰富的权限权利和完善的架构设计,适用大规模docker集群部署提供仓库服务.项目地址:ht ...