现在的位置: 首页 > 综合 > 正文

Android Build 系统

2013年02月25日 ⁄ 综合 ⁄ 共 3463字 ⁄ 字号 评论关闭

http://www.ibm.com/developerworks/cn/opensource/os-cn-android-build/index.html#iratings
前言

AndroidBuild
系统是Android源码的一部分。关于如何获取Android源码,请参照AndroidSource
官方网站:

http://source.android.com/source/downloading.html

AndroidBuild
系统用来编译Android系统,AndroidSDK
以及相关文档。该系统主要由Make文件,Shell脚本以及Python脚本组成,其中最主要的是Make文件。

众所周知,Android是一个开源的操作系统。Android的源码中包含了大量的开源项目以及许多的模块。不同产商的不同设备对于Android系统的定制都是不一样的。

如何将这些项目和模块的编译统一管理起来,如何能够在不同的操作系统上进行编译,如何在编译时能够支持面向不同的硬件设备,不同的编译类型,且还要提供面向各个产商的定制扩展,是非常有难度的。

AndroidBuild
系统很好的解决了这些问题,这里面有很多值得我们开发人员学习的地方。

对于Android平台开发人员来说,本文可以帮助你熟悉你每天接触到的构建环境。

对于其他开发人员来说,本文可以作为一个GNUMake
的使用案例,学习这些成功案例,可以提升我们的开发经验。

回页首

概述

Build系统中最主要的处理逻辑都在Make文件中,而其他的脚本文件只是起到一些辅助作用,由于篇幅所限,本文只探讨Make文件中的内容。

整个Build系统中的Make文件可以分为三类:

第一类是Build系统核心文件,此类文件定义了整个Build系统的框架,而其他所有Make文件都是在这个框架的基础上编写出来的。

1Android源码树的目录结构,Build系统核心文件全部位于/build/core(本文所提到的所有路径都是以Android源码树作为背景的,“/”指的是源码树的根目录,与文件系统无关)目录下。


1.Android
源码树的目录结构
图 1. Android 源码树的目录结构 

第二类是针对某个产品(一个产品可能是某个型号的手机或者平板电脑)的Make文件,这些文件通常位于device目录下,该目录下又以公司名以及产品名分为两级目录,图2device目录下子目录的结构。对于一个产品的定义通常需要一组文件,这些文件共同构成了对于这个产品的定义。例如,/device/sony/it26目录下的文件共同构成了对于SonyLT26
型号手机的定义。


2.device
目录下子目录的结构
图 2. device 目录下子目录的结构 

第三类是针对某个模块(关于模块后文会详细讨论)的Make文件。整个系统中,包含了大量的模块,每个模块都有一个专门的Make文件,这类文件的名称统一为“Android.mk”,该文件中定义了如何编译当前模块。Build系统会在整个源码树中扫描名称为“Android.mk”的文件并根据其中的内容执行模块的编译。

回页首

编译Android系统

执行编译

Android系统的编译环境目前只支持Ubuntu以及MacOS两种操作系统。关于编译环境的构建方法请参见以下路径:http://source.android.com/source/initializing.html

在完成编译环境的准备工作以及获取到完整的Android源码之后,想要编译出整个Android系统非常的容易:

打开控制台之后转到Android源码的根目录,然后执行如清单1所示的三条命令即可("$"是命令提示符,不是命令的一部分。):

完整的编译时间依赖于编译主机的配置,在笔者的MacbookProOSX
10.8.2, i7 2G CPU
8GRAM, 120G
SSD
)上使用8Job同时编译共需要一个半小时左右的时间。


清单1.编译Android系统

                                
 $ source build/envsetup.sh 
 $ lunch full-eng 
 $ make -j8 

这三行命令的说明如下:

第一行命令“sourcebuild/envsetup.sh”引入了 build/envsetup.sh脚本。该脚本的作用是初始化编译环境,并引入一些辅助的Shell函数,这其中就包括第二步使用lunch函数。

除此之外,该文件中还定义了其他一些常用的函数,它们如表1所示:


1.build/envsetup.sh
中定义的常用函数

名称

说明

croot

切换到源码树的根目录

m

在源码树的根目录执行make

mm

Build当前目录下的模块

mmm

Build指定目录下的模块

cgrep

在所有 C/C++文件上执行grep

jgrep

在所有 Java文件上执行grep

resgrep

在所有 res/*.xml文件上执行grep

godir

转到包含某个文件的目录路径

printconfig

显示当前 Build的配置信息

add_lunch_combo

lunch函数的菜单中添加一个条目

第二行命令“lunchfull-eng”是调用lunch函数,并指定参数为“full-eng”lunch函数的参数用来指定此次编译的目标设备以及编译类型。在这里,这两个值分别是“full”和“eng”。“full”Android源码中已经定义好的一种产品,是为模拟器而设置的。而编译类型会影响最终系统中包含的模块,关于编译类型将在表7中详细讲解。

如果调用lunch函数的时候没有指定参数,那么该函数将输出列表以供选择,该列表类似图3中的内容(列表的内容会根据当前Build系统中包含的产品配置而不同,具体参见后文“添加新的产品”),此时可以通过输入编号或者名称进行选择。


3.lunch
函数的输出
图 3. lunch 函数的输出 

第三行命令“make-j8”才真正开始执行编译。make的参数“-j”指定了同时编译的Job数量,这是个整数,该值通常是编译主机CPU支持的并发线程总数的1倍或2倍(例如:在一个4核,每个核支持两个线程的CPU上,可以使用make-j8
make-j16)。在调用make命令时,如果没有指定任何目标,则将使用默认的名称为“droid”目标,该目标会编译出完整的Android系统镜像。

Build结果的目录结构

所有的编译产物都将位于/out目录下,该目录下主要有以下几个子目录:

  • /out/host/:该目录下包含了针对主机的Android开发工具的产物。即SDK中的各种工具,例如:emulatoradbaapt等。

  • /out/target/common/:该目录下包含了针对设备的共通的编译产物,主要是Java应用代码和Java库。

  • /out/target/product/<product_name>/:包含了针对特定设备的编译结果以及平台相关的C/C++库和二进制文件。其中,<product_name>是具体目标设备的名称。

  • /out/dist/:包含了为多种分发而准备的包,通过“makedisttarget将文件拷贝到该目录,默认的编译目标不会产生该目录。

Build生成的镜像文件

Build的产物中最重要的是三个镜像文件,它们都位于/out/target/product/<product_name>/目录下。

这三个文件是:

  • system.img:包含了AndroidOS
    的系统文件,库,可执行文件以及预置的应用程序,将被挂载为根分区。

  • ramdisk.img:在启动时将被Linux内核挂载为只读分区,它包含了/init文件和一些配置文件。它用来挂载其他系统镜像并启动init进程。

  • userdata.img:将被挂载为/data,包含了应用程序相关的数据以及和用户相关的数据。

回页首

Make文件说明

整个Build系统的入口文件是源码树根目录下名称为“Makefile”的文件,当在源代码根目录上调用make命令时,make命令首先将读取该文件。

Makefile文件的内容只有一行:“includebuild/core/main.mk。该行代码的作用很明显:包含build/core/main.mk文件。在main.mk文件中又会包含其他的文件,其他文件中又会包含更多的文件,这样就引入了整个Build系统。

这些Make文件间的包含关系是相当复杂的,图3描述了这种关系,该图中黄色标记的文件(且除了 $开头的文件)都位于build/core/目录下。


4.主要的Make文件及其包含关系
图 4. 主要的 Make 文件及其包含关系 

2总结了图4中提到的这些文件的作用:


2.主要的Make文件的说明

文件名

抱歉!评论已关闭.