一、预习Makefile
二、Android编译系统的层次
三、Android编译系统的常用配置文件
四、Android编译系统的流程
五、Android编译系统的使用
一、预习Makefile
Makefile的规则:
target ... : prerequisites ...
command
...
...
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label)。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,
其生成规则定义在command中。 说白一点就是说,prerequisites中如果有一个以上的文件比target文
件要新的话,command所定义的命令就会被执行。这就是 Makefile的规则。也就是Makefile中最核心的
内容。正如上面作者所述,上面是Makefile中最核心的内容,Android编译系统符合GNU make的标准,
当然这也是Android 编译系统最核心的内容。
二、Android编译系统的层次
Android编译系统(build system)集中于Android源码下的build/core下,在Android2.2中,共有
56个*.mk文件。另外还有一些shell脚本。Android编译系统完成的并不仅仅是对目标(主机)系统二进
制文件、java应用程序的编译、链接、打包等,而且还有包括生成各种依赖关系、确保某个模块的修改引起
相依赖的文件的重新编译链接,甚至还包括目标文件系统的生成,配置文件的生成等,因此Android编译系
统具有支持多架构(linux-x86、windows、arm等)、多语言(汇编、C、C++、Java等)、多目标、多
编译方式。
编译层次包含了下表描述的抽象层。每一层都与一个或多个层相关联。例如,一个arch有多个board,每个
board有多个device。你可以在一个层中定义一个元素,以达到排除复制,简化维护的目的。
Layer Example Description
Product myProduct, myProduct_eu, j2, sdk 产品层定义完整的移植产品的语法。
myProduct_eu_fr, 定义要编译哪些模块,怎么配置。基于区域
或者基于特性,比如照相机,你可能要提供几
个不同的版本。
Device myDevice, myDevice_eu, 设备层代表设备的物理层。例如,北美设备可
myDevice_eu_lite 能包含QWERTY键盘,而在法国售卖的设备可能
包含AZERTY键盘。外围设备一般与设备层连接
Board sardine, trout, goldfish 电路板层代表产品的原始图。可能还有外围设备
连接到这一层。
Arch arm (arm5te) (arm6), x86, 68k 体系层描述了在电路版上运行的处理器。
三、Android编译系统的常用配置文件
在Android中,主要的Makefile文件存在于build/core/目录下,它的表现形式为多个后缀为mk的文件组
成,也称为build system。Android build system 主要有两大部分构成:配置部分,目标构建部分。
Build system的主流程文件为build/core/main.mk文件。
几个很重要的*.mk文件如下:
buildspec.mk:位于根目录下,可在此选择要产生的product 、平台、额外的module/package等。
build/buildspec.mk.default是样板。
AndroidProducts.mk:即为Android build system提供给厂商的接口文件。通过此文件即可定义所
需编译和安装的packages(也即应用程序)。缺省选项是generic。
BoardConfig.mk:是为product主板做设定,例如driver选择设定,选择CPU架构等等。
Android.mk:是 module 和 package 的设置文件,每个 module/package 的目录下都会有一个
Android.mk。所谓的 module 是指系统的 native code ,相对于用 Java写成的
Androidapplication 称为 package。
Build/envsetup.mk:编译环境初始化,定义一些实用的shell函数,方便编译使用。
build/core/Makefile:包含build/core/main.mk,此文件主要控制生成
system.img,ramdisk.img,userdata.img,以及recorvery image,sdk等。
main.mk:实际的主控Makefile,例如找到TOP目录下所有Android.mk文件。
config.mk:定义了编译目标程序所需的工具链及编译参数。
base_rules.mk:对一些Makefile的变量规则化
Binary.mk:控制如何生成目标文件
Clear_vars.mk:清除编译系统中用到的临时变量
definations.mk:定义了很多编译系统中用到的宏,相当于函数库
Copy_headers.mk:将头文件拷贝到指定目录
Combo/linux-arm.mk:控制如何生成linux-arm二进制文件,包括ARM相关的编译器,编译参数等的
设置
build/envsetup.sh:提供了几个有用的命令,执行 . build/envsetup.sh(.后面有空格)。
注:其中对模块编译有帮助的是tapas、m、mm、mmm这几个命令。
1、tapas——以交互方式设置build环境变量。
输入:tapas
第一步,选择目标设备:
例如 我们选择1
第二步,选择代码格式:
我们选择1
第三步,选择产品平台:
注意:这里,Google源代码里默认是generic。
2、m、mm、mmm使用独立模块的make命令
m 从根目录开始编译;
mm 编译当前目录下的所有模块;
mmm 编译指定目录下的所有模块;
四、Android编译系统的流程
主要流程都是由 build/core/main.mk 所安排的。
1、初始化相关变量
2、检测编译环境和目标环境
3、决定目标product
4、读取 product 的设定
5、读取 product 所指定之目标平台架构设定
6、选择 toolchain
7、指定编译参数 (*-.mk)
8、清除输出目录
9、设定/检查版本编号
10、读取所有 BoardConfig.mk 文件
11、读取所有 module 的设定
12、根据设定,产生必需的 rule
13、产生 image
1、初始化和检测
由 build/core/config.mk 进行。 build/core/envsetup.mk 检查 developer 的设定
(buildspec.mk),并检查执行环境,以决定输出目录和环境。build/core/config.mk 本身还依据
参数,决定解释时的相关参数,例如 compiler 的路径、flags, lex 、yacc 的路径参数等。关于
product的相关设定,则是由build/core/product_config.mk 所处理,使用
build/core/product.mk提供之 macro 载入。根据 AndroidProduct.mk 的內容,
product_config.mk 决定了:PRODUCT_TAGS,OTA_PUBLIC_KEYS,PRODUCT_POLICY等。
2、Product 设定的读取
Android product 的设定来自于build/target/product/AndroidProduct.mk 和 vendor 子目
录下AndroidProduct.mk 。building system透过 find 指令,找出所有可能的
AndroidProduct.mk。AndroidProduct.mk里定义PRODUCT_MAKEFILES变量,列举所有实际定义
product的 makefile。这些makefile 各自定义独立的 product。product 相关参数,存成
PRODUCTS. . 形式的变量。并将makefile 路径存在 PRODUCTS 变量。因此,透过 PRODUCTS 能取
得所有的 product 路径/名称,并透过 PRODUCTS. . 形式的变量取得內容。
3、Module 设定的读取
Module 是指 native code 的软件模块,而 Java application 則被称为 package。
build/core/definitions.mk 定义module/package 相关 macro ,读取、检查
module/package 定义档;分散 source tree 各处的 Android.mk 文件。
build/core/main.mk 使用 find 指令,在这些子目录下找出所有 Android.mk ,并将路径存在
subdir_makefiles 变量里。最后,include 这些文件。这些Android.mk 会 include 定义成变量
BUILD_SHARED_LIBRARY 、BUILD_PACKAGE 等,和其目的相配的 makefile。这些 makefile 会
变 Android.mk 定义之內容,存成 ALL_MODULES. Android.mk>. 的形式。例如,Android.mk 定
义了LOCAL_MODULE_SUFFIX ,会变存成 ALL_MODULES.
Android.mk>.LOCAL_MODULE_SUFFIX 。而 Android.mk 路径, 同样会存于ALL_MODULES 变量
里。查找 Android.mk 的路径,基本上会是整个 source tree 。但会依特定的 goal , 选择性只
找寻特定目录。例如 SDK 只需特定目录下的 Android.mk 。
4、Board Level 设定
和目标平台主板相关之设定,例如使用了什么装置、driver 等,或是是否需要编译bootloader 、
kernel等,都是在 BoardConfig.mk 里设定。同样,每张主板可以有不同设定,存在不同目录下的
BoardConfig.mk,以 find 寻找如下文件:
build/target/board/$(TARGET_DEVICE)/BoardConfig.mk
device/*/$(TARGET_DEVICE)/BoardConfig.mk
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk
TARGET_DEVICE 是 product 所定义,因此同一个 BoardConfig.mk 可被多个 product 所使用。
一个 TARGET_DEVICE ,通常只有一个 BoardConfig.mk 。 BoardConfig.mk 会被直接
include 到 building system 的 name space 里。 因此,一些 module 的
enable/disable ,可以在 BoardConfig.mk 以对应不同的主板。
5、Rules
在 module 的定义文件 Android.mk 裡,可定义 module 的 tag, LOCAL_MODULE_TAGS, 以分
类这些 module。每一个 product 可以指定需要的 tag (PRODUCT_TAGS),使 building system
只便宜标示这些 tag 的 module。在 build/core/main.mk 里,所有标示特定 tag 的 module 收
集为 ALL_DEFAULT_INSTALLED_MODULES,并 include build/core/Makefile 处理。
build/core/Makefile 为这些 module 产生 rule ,并使产生 image 的 goal depend on 这
些 rule ,使这些 module 被编译。
五、Android编译系统的使用
下面两种方法,第一个产生更稳定的结果。
方法一:
创建buildspec.mk的本地版本。最容易的方法是进入你的设备目录,
执行下列指令:
cp buildspec.mk.default buildspec.mk ; chmod u=rw buildspec.mk
默认的buildspec.mk文件,所有的选项都是被注释的,为了建立个性化的配置环境,可以编辑
buildspec.mk.
一般设置如下选项就可以拉:
BUILD_ENV_SEQUENCE_NUMBER := 9
TARGET_BOARD_PLATFORM := imx53
TARGET_PRODUCT := mine_mx53
一旦建立了配置文件,然后复制到根目录下,就能够通过执行make编译设备代码,在第一次执行这个命令
的时候,会花费很长时间,在双核机器上,考虑使用’-j2’(甚至’j4’)以加速编译。
make -j2
方法二:
做一个通用的版本,
执行
source //device/envsetup.sh, 这个文件包含了必要的变量和函数定义,下面有描述:
cd $TOP
.envsetup.sh
partner_setup generic //select generic as the product
make -j4 PRODUCT-generic-user
//你也可以用eng替换user, 生成一个调式版。
make -j4 PRODUCT-generic-eng