设定档
Android building system包括几种重要的设定档,
- Android .mk
- AndroidProducts.mk
- target_<os>-.mk, host_-.mk and -.mk
- BoardConfig.mk
- buildspec.mk
Android .mk是module和package的设定档,每个module/package的目录下都会有一个Android.mk。所谓的module是指系统的native code ,相对于用Java写成的Android application称为package。
AndroidProducts.mk 则设定product 配置。product 即特定系统版本,透过编译不同product ,产生不同软体配置内容,安装不同的application。Product 可视为特定专案,产生特定规格系统。
BoardConfig.mk 是为product 主板做设定,像是driver 选择、 设定。*-.mk 则是针对选择的作业系统和CPU 架构,进行相关设定。
buildspec.mk 是位于source 根目录下,为进行编译者所做之额外设定。例如,可在此选择要产生的product 、平台、额外的module/package 等。
参数
build/envsetup.sh实作一个mm指令,以编译单一module,不需编译整个source tree。ONE_SHOT_MAKEFILE这个makefile变数/参数就是用以实作这个功能。使用方法是在执行make时,将该变数指定为module的Android .mk。
- make ONE_SHOT_MAKEFILE=
透过定义CREATE_MODULE_INFO_FILE , building system 会将所有module 资讯列在$(PRODUCT_OUT)/module-info.txt 档案里。
- make CREATE_MODULE_INFO_FILE=true
设定BUILD_TINY_ANDROID=true , building system 产生一个简单的image , 以测试硬体的可用度。此功能用于移植的早期阶段,以快速bring up 。
HOST_BUILD_TYPE 和TARGET_BUILD_TYPE 指定building system 产生binary 的目的为debug 或release 。透过设定此二变数,能产生包含debug information 的binry 。
- debug
- release
这些参数,也可设于buildspec.mk 里,以避免开发过程不断的重新指定。
Goals
一般编辑整个Android系统,就是使用droid这个goal。droid会产生一个完整的系统,包括bootloader、kernel、系统程式、模组和应用程式。
showcommands 和droid 功能相同,但droid 在编译过程不显示所使用的指令。透过showcommands 这个goal, building system 显示过程中每一个步骤的详细指令。
Makefile 的流程
- 初始化相关变数
- 侦测编译环境和目标环境
- 决定目标product
- 读取product 的设定
- 读取product 所指定之目标平台架构设定
- 选择toolchain
- 指定编译参数(*-.mk)
- 清除输出目录
- 设定/检查版本编号
- 读取所有BoardConfig.mk 档案
- 读取所有module 的设定
- 根据设定,产生必需的rule
- 产生image
以上的主要流程都是由build/core/main.mk 所安排。
初始化和侦测
由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
- ......
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.. 形式的变数取得内容。
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.<path of="" Android.mk>.形式。例如, Android .mk定义了LOCAL_MODULE_SUFFIX ,变会存成ALL_MODULES.<path of="" Android.mk>.LOCAL_MODULE_SUFFIX 。而Android .mk路径,当样会存于ALL_MODULES变数里。
Search Android .mk的路径,基本上会是整个source tree 。但会依特定的goal ,选择性只找寻特定目录。例如SDK只需特定目录下的Android .mk 。
Board Level 设定
和目标平台主板相关之设定,例如使用了什么装置、driver 等,或是是否需要编译bootloader 、 kernel 等,都是在BoardConfig.mk 里设定。同样,每张主板可以有不同设定,存在不同目录下的BoardConfig.mk ,以find 寻找如下档案:
- build/target/board/$(TARGET_DEVICE)/BoardConfig.mk
- vendor/*/$(TARGET_DEVICE)/BoardConfig.mk
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的building system其实不是那么复杂。在了解之后,也不是那么难修改。但, GNU make的一些语法,所building system使用一些不是那么直觉的用法,使的building system较难了解。但,花点心思就能克服。