Android编译系统简要

Android Build 系统可以使用Android.mk文件通过m/mm/mmm/make等命令进行编译,make命令还可制作各种系统镜像文件,例如system.img、boot.img和recovery.img等。这一切都得益于Android编译系统,它为我们处理了各种依赖关系,以及提供各种有用工具。

Android Build系统中最主要的处理逻辑都在Make文件中,而其他脚本文件只是起到一些辅助作用。Make命令在执行的时候,默认会在当前目录找到一个Makefile文件,然后根据Makefile文件中的指令来对代码进行编译。也就是说,make命令执行的是Makefile文件中的指令。

Android Build系统中Make文件可以分为三类:

  • 第一类是Build系统核心文件,此类文件定义了整个Build系统框架,而其他所有Make文件都是在这个框架的基础上编写出来的。Build系统核心文件全部位于/build/core/
  • 第二类是针对某个产品(一个产品可能是某个型号的手机或者平板电脑)的Make文件,这些文件通常位于/device目录下,该目录又以公司以及产品名分为两级目录/device/公司/产品,/device下还包含一些芯片平台相关的Make文件。
  • 第三类是针对某个模块的Make文件。整个系统中,包含大量的模块,每个模块都有一个专门的Make文件,这类文件的名称统一为“Android.mk”,该文件中定义了如何编译当前模块。Android Build系统会在这个源码树种扫描名称为“Android.mk”的文件并根据其中的内容执行模块编译。

编译Android系统

编译Android系统三部曲:

  • source build/envsetup.sh
  • lunch full-eng
  • make -j24

这三行命令的说明如下:

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

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

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

名称说明
croot切换到源码树的根目录
m在源码树的根目录执行 make
mmBuild 当前目录下的模块
mmmBuild 指定目录下的模块
cgrep在所有 C/C++ 文件上执行 grep
jgrep在所有 Java 文件上执行 grep
resgrep在所有 res/*.xml 文件上执行 grep
godir转到包含某个文件的目录路径
printconfig显示当前 Build 的配置信息
add_lunch_combo在 lunch 函数的菜单中添加一个条目

第二行命令“lunch full-eng”是调用 lunch 函数,并指定参数为“full-eng”。lunch 函数的参数用来指定此次编译的目标设备以及编译类型。在这里,这两个值分别是“full”和“eng”。“full”是 Android 源码中已经定义好的一种产品,是为模拟器而设置的,而编译类型会影响最终系统中包含的模块,关于编译类型可以参考alps/build/core/build-system.html 说明。

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

第三行命令“make -j24”才真正开始执行编译。make 的参数“-j”指定了同时编译的 Job 数量,这是个整数,该值通常是编译主机 CPU 支持的并发线程总数的 1 倍或 2 倍(例如:在一个 4 核,每个核支持两个线程的 CPU 上,可以使用 make -j8 或 make -j16)。

Build 结果的目录结构

  • /out/host/:该目录下包含了针对主机的 Android 开发工具的产物。即 SDK 中的各种工具,例如:emulator,adb,aapt 等
  • /out/target/common/:该目录下包含了针对设备的共通的编译产物,主要是 Java 应用代码和 Java 库
  • /out/target/product/<product_name>/:包含了针对特定设备的编译结果以及平台相关的 C/C++ 库和二进制文件。其中,<product_name>是具体目标设备的名称

Make文件说明

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

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

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

主要的 Make 文件的说明

文件名说明
main.mk最主要的 Make 文件,该文件中首先将对编译环境进行检查,同时引入其他的 Make 文件。另外,该文件中还定义了几个最主要的 Make 目标,例如 droid,sdk,等(参见后文“Make 目标说明”)。
help.mk包含了名称为 help 的 Make 目标的定义,该目标将列出主要的 Make 目标及其说明。
pathmap.mk将许多头文件的路径通过名值对的方式定义为映射表,并提供 include-path-for 函数来获取。例如,通过 $(call include-path-for, frameworks-native)便可以获取到 framework 本地代码需要的头文件路径。
envsetup.mk配置 Build 系统需要的环境变量,例如:TARGET_PRODUCT,TARGET_BUILD_VARIANT,HOST_OS,HOST_ARCH 等。
当前编译的主机平台信息(例如操作系统,CPU 类型等信息)就是在这个文件中确定的。
另外,该文件中还指定了各种编译结果的输出路径。
combo/select.mk根据当前编译器的平台选择平台相关的 Make 文件。
dumpvar.mk在 Build 开始之前,显示此次 Build 的配置信息。
config.mk整个 Build 系统的配置文件,最重要的 Make 文件之一。该文件中主要包含以下内容:
  • 定义了许多的常量来负责不同类型模块的编译。
  • 定义编译器参数以及常见文件后缀,例如 .zip,.jar.apk。
  • 根据 BoardConfig.mk 文件,配置产品相关的参数。
  • 设置一些常用工具的路径,例如 flex,e2fsck,dx。
definitions.mk最重要的 Make 文件之一,在其中定义了大量的函数。这些函数都是 Build 系统的其他文件将用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package 等,关于这些函数的说明请参见每个函数的代码注释。
distdir.mk针对 dist 目标的定义。dist 目标用来拷贝文件到指定路径。
dex_preopt.mk针对启动 jar 包的预先优化。
pdk_config.mk顾名思义,针对 pdk(Platform Developement Kit)的配置文件。
${ONE_SHOT_MAKEFILE}ONE_SHOT_MAKEFILE 是一个变量,当使用“mm”编译某个目录下的模块时,此变量的值即为当前指定路径下的 Make 文件的路径。
${subdir_makefiles}各个模块的 Android.mk 文件的集合,这个集合是通过 Python 脚本扫描得到的。
post_clean.mk在前一次 Build 的基础上检查当前 Build 的配置,并执行必要清理工作。
legacy_prebuilts.mk该文件中只定义了 GRANDFATHERED_ALL_PREBUILT 变量。
Makefile被 main.mk 包含,该文件中的内容是辅助 main.mk 的一些额外内容

Android编译系统变化

1.1 编译系统变化

从Android 7.0开始,Android的编译系统发生了变化,之前依赖Make文件组织编译系统,从7.0开始逐步引入Kati soong(optional为正式使用,需要USE_SOONG=true开启),将Android.mk文件转化成ninja文件,使用ninja文件对编译系统进行管理。

从Android 8.0开始,Android引入了Android.bp文件来替换之前的Android.mk文件,与Android.mk不同的是,Android.bp是纯粹的配置文件,不包含分支、循环等流程控制,也不能做算数、逻辑运算。 与此同时,ninja文件也是如此。 这就产生了一些新的问题与需求——在Android项目上进行选择编译、解析配置、转换成ninja等——Soong应运而生。Soong其实就相当于Makefile编译系统的核心,即build/make/core/下面的内容。 它负责提供Android.bp的含义定义与解析,并将之转换为ninja文件。。

此外,Soong还会编译产生一个androidmk命令,可以手动把Android.mk转换成Android.bp。 这只对无选择、循环等复杂流程控制的Android.mk生效。

Blueprint和Soong都是由Go语言写的项目。 从Android Nougat开始,prebuilts/go/目录下新增了Go语言所需的运行环境,在编译时使用。

Android.bp以及相关支持,从Android Nougat开始加入,从Android Oreo(8.0)开始默认开启。 如果需要在Android Nougat的版本使用,需要在执行编译时添加变量。

make 'USE_SOONG=true'

1.2 代码路径变化

Kati的位置是在build/kati中

Soong的位置在build/soong

1.3 工具链关系

Android.mk、Android.bp、Soong、Buleprint、Ninja,它们之间到底有什么关系? 以下用简单的方式表达这几个概念之间的作用关系。

Android.bp --> Blueprint --> Soong --> Ninja
Makefile or Android.mk --> kati --> Ninja

(Android.mk --> Soong --> Blueprint --> Android.bp)

Blueprint是生成、解析Android.bp的工具,是Soong的一部分。 Soong则是专为Android编译而设计的工具,Blueprint只是解析文件的形式,而Soong则解释内容的含义。

Android.mk可以通过Soong提供的androidmk转换成Android.bp,但仅限简单配置。 目前Oreo的编译流程中,仍然是使用kati来做的转换。

现存的Android.mk、既有的Android.bp,都会分别被转换成Ninja。 从Android.mk与其它Makefile,会生成out/build-<product_name>.ninja文件。 而从Android.bp,则会生成out/soong/build.ninja。 此外,还会生成一个较小的out/combined-<product_name>.ninja文件,负责把二者组合起来,作为执行入口。

最终,Ninja文件才是真正直接控制源码编译的工具。在编译过程中,将所有的Android.bp文件收集成out/soong/build.ninja.d,并以此为基础生成out/soong/build.ninja规则

总结为:在原先Android 6.0纯Makefile编译的传统流程前,8.0版本新增了四个步骤:

  1. Soong的自举(bootstrap)。这个步骤会编译Soong的核心组件。
  2. 收集Android.bp并生成out/soong/build.ninja文件。
  3. 收集Android.mk并生成out/build-<product>.ninjaout/combined-<product>.ninja文件。
  4. 执行Ninja文件,进行编译。这个combined-*.ninja文件,就是真正的执行入口。

后面的步骤就是自底向上编译Android所有模块,与以前相同。

 

参考:

https://www.ibm.com/developerworks/cn/opensource/os-cn-android-build/index.html

http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359.html

http://note.qidong.name/2017/08/android-blueprint/

https://zhuanlan.zhihu.com/p/33259915

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值