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 适合谁来阅读? 本系列文章尽量使用最浅显易懂的文字.图片来组织内容,力求通信技术零基础的人群也能看懂.但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获.如果您大 ...
随机推荐
- EditText自动换行显示内容
默认的EditText是不会自动换行的,通过代码来实现: [java] view plain copy EditText editText = new EditText(this); //设置Edit ...
- document.domain 实现跨域
该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式. 只需要给页面添加 document.domain = 'test.com' 表示二级域名都相同 ...
- MongoDB中MapReduce介绍与使用
一.简介 在用MongoDB查询返回的数据量很大的情况下,做一些比较复杂的统计和聚合操作做花费的时间很长的时候,可以用MongoDB中的MapReduce进行实现 MapReduce是个非常灵活和强大 ...
- opencv-android笔记1:android studio 2.3 + opencv-android-sdk 实现 camera预览
Android studio环境配置不再赘述,可以参照我的其他博客. Android应用程序开发环境搭建:http://blog.csdn.net/ja33son/article/details/61 ...
- mark 阿里支付
开源软件企业版特惠高校版博客 我的码云 ·· 8月18日(周六)成都源创会火热报名中,四位一线行业大牛与你面对面,探讨区块链技术热潮下的冷思考. 开源项目 > WEB应用开发 > Web开 ...
- CentOS7安装chrony替代ntp同步时间
Chrony是一个开源的自由软件,它能保持系统时钟与时钟服务器(NTP)同步,让时间保持精确.它由两个程序组成:chronyd和chronyc:chronyd是一个后台运行的守护进程,用于调整内核中运 ...
- DataTables 全局设置中文语言
参考来源:https://blog.csdn.net/qq_22690445/article/details/79682311 $.fn.dataTable.defaults.oLanguage = ...
- 转:pycharm community debug django projects
原文:https://automationpanda.com/2017/09/14/django-projects-in-pycharm-community-edition/comment-page- ...
- Error:java: invalid source release 无效的源发行版: 8
原因:这是由于jdk的版本与项目的要求不一致造成的,如果是maven项目,首先查看一下pom.xml,以我的项目为例: 从其中可以看出要求的编译插件为1.8版本,而我本机上安装的jdk为1.7版本,因 ...
- WebApi XML,Json格式自定义,IEnumerable<T>,ArrayOf
global.ascx中application-start() GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSeri ...