Android编译系统——基础介绍(一)

Android 编译系统是构建 Android 操作系统及其应用程序的基础设施。它负责将源代码、资源文件以及其他组件编译并打包成可以在 Android 设备上运行的软件包(如APK或系统镜像)。理解 Android 编译系统对于开发人员来说至关重要。

一、编译系统介绍

在 Android 7.0 之前,Android 编译系统使用 GNU Make 描述和 shell 来构建编译规则,模块定义都使用 Android.mk 进行定义,Android.mk 的本质就是 Makefile,但是随着 Android 的工程越来越大,模块越来越多,Makefile 组织的项目编译时间越来越长。因此,从 Android7.0 开始,Google 采用 ninja 来取代之前使用的 make,但由于之前的 Android.mk 数据量比较巨大,因此 Google 加入了一个 kati 工具,用于将 Android.mk 转换成 ninja 的构建规则文件 buildxxx.ninja,再使用 ninja 来进行构建工作。

此次重构的最终目标是要把 make 都取代,于是从 Android8.0 开始,Google 为了进一步淘汰 Makefile,因此引入了 Android.bp 文件来替换之前的 Android.mk。Android.bp 只是一个纯粹的配置文件,不包括分支、循环语句等控制流程,本质上就是一个 json 配置文件。Android.bp 通过 Blueprint + soong 转换成 ninja 的构建规则文件 build.ninja,再使用 ninja 来进行构建工作。

Android 10.0 上,mk 和 bp 编译的列表可以从 \out.module_paths 中的 Android.bp.list、Android.mk.list 中看到,Android 10.0 还有 400 多个 mk 文件没有被替换完。到 Android 12 中完全迁移到 m 和 mmm 等封装脚本,底层仅通过 Soong 和 Ninja 运行,更多系统组件从 Android.mk 迁移到 Android.bp,尤其是 HAL 和内核模块。

1、编译演进过程

  • Android 7.0 之前使用 GNU Make;
  • Android 7.0 引入 ninja、kati、Android.bp 和 soong 构建系统;
  • Android 8.0 默认打开 Android.bp;
  • Android 9.0 强制使用 Android.bp。

Google 在 Android 7.0 之后,引入了 Soong 构建系统,旨在取代 make,它 利用 Kati GNU Make 克隆工具和 Ninja 构建系统组件来加速 Android 的构建。

Make 构建系统得到了广泛的支持和使用,但在 Android 层面变得缓慢、容易出错、无法扩展且难以测试。Soong 构建系统正好提供了 Android build 所需的灵活性。

2、系统编译历程

二、编译流程

1、编译构成

Android 的编译目录在 /build 中,看一下 Android 10.0 源码中的 build 目录,现在是这个样子:

这个目录中可以看到 core 文件夹被 link 到了 make/core,envsetup.sh 被 link 到 make/envsetup.sh,这主要是为了对使用者屏蔽切换编译系统的差异。这里重点看四个文件夹 blueprint、kati、make 和 soong:

  • blueprint:用于处理 Android.bp,编译生成 *.ninja 文件,用于做 ninja 的处理;

  • kati:用于处理 Android.mk,编译生成 *.ninja 文件,用于做 ninja 的处理;

  • make:文件夹还是原始的 make 那一套流程,比如 envsetup.sh

  • soong:构建系统,核心编译为 soong_ui.bash。

2、Soong编译系统

先来看一下 Soong 编译系统家族成员及各自关系:

  • 在编译过程中,Android.bp 会被收集到 out/soong/build.ninja.d,blueprint 以此为基础,生成 out/soong/build.ninja;

  • Android.mk 会由 kati/ckati 生成为 out/build-aosp_arm.ninja;

  • 两个 ninja 文件会被整合进入 out/combined-aosp_arm.ninja。

combined-aosp_arm.ninja

php 复制代码
builddir = out
pool local_pool
 depth = 42
build _kati_always_build_: phony
subninja out/build-aosp_arm.ninja
subninja out/build-aosp_arm-package.ninja
subninja out/soong/build.ninja

编译过程

执行 runKatiBuild 时有个重要的步骤,就是加载 build/make/core/main.mk,main.mk 文件是 Android Build 系统的主控文件。从 main.mk 开始,将通过 include 命令将其所有需要的 .mk 文件包含进来,最终在内存中形成一个包括所有编译脚本的集合,这个相当于一个巨大 Makefile 文件。Makefile 文件看上去很庞大,其实主要由三种内容构成:变量定义、函数定义和目标依赖规则,此外 mk 文件之间的包含也很重要。

3、编译步骤

source build/envsetup.sh // 初始化编译环境

lunch aosp_arm // 选择平台编译选项(编号或名称),只执行 lunch 可以查看所有选项

make -j8 // 执行编译命令,-j8 表示使用多少个线程去编译

4、关键mk文件

文件 说明
build/make/core/main.mk Build的主控文件,主要作用是包含其他mk,以及定义几个最重要的编译目标,同时检查编译工具的版本,例如如gcc、clang、java等
build/make/core/config.mk Build的配置文件,主要是区分各个产品的配置,并将这些编译器参数引入产品配置BoardConfig.mk,同时也配置了一些编译器的路径等
build/make/core/clang/config.mk clang编译的配置文件
build/make/core/definitions.mk 最重要的Make 文件之一,在其中定义了大量的函数。这些函数都是Build 系统的其他文件将用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package 等,关于这些函数的说明请参见每个函数的代码注释
build/make/core/dex_preopt.mk 定义了dex优化相关的路径和参数
build/make/core/pdk_config.mk 编译pdk的配置文件
build/make/core/Makefile 系统最终编译完成所需要的各种目标和规则
build/make/core/envsetup.mk 包含进product_config.mk文件并且根据其内容设置编译产品所需要的环境变量,并检查合法性,指定输出路径等
build/make/core/combo/select.mk 根据当前编译器的平台选择平台相关的 Make 文件
build/make/core/ninja_config.mk 解析makefile的的列表,传给kati,配置传给ninja和kati的目标
build/make/core/soong_config.mk 配置soong的环境变量,建立go变量和mk变量的json映射关系,让go变量可以获取到mk中定义的变量值

mk文件关系

三、编译工具链

Android 10.0 的编译系统中,涉及以下一些工具链,由这些工具链相辅相成,才最终编译出了我们所需要的镜像版本。Android10.0 编译工具链:

bash 复制代码
soong\kati\blueprint\ninja 

1、Soong

Soong 构建系统是在 Android 7.0 (Nougat) 中引入的,旨在取代 Make。它利用 Kati GNU Make 克隆工具和 Ninja 构建系统组件来加速 Android 的构建。

Soong 是由 Go 语言写的一个项目,从 Android 7.0 开始,在 prebuilts/go/ 目录下新增了 Go 语言所需的运行环境,Soong 在编译时使用,解析 Android.bp,将之转化为 Ninja 文件,完成 Android 的选择编译,解析配置工作等。故 Soong 相当于 Makefile 编译系统的核心,即 build/make/core 下面的内容。

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

soong 脚本和代码目录:/build/soong

2、kati

kati 是一个基于 Makefile 来生成 ninja.build 的小项目。主要用于把 Makefile 转成成 ninja file,自身没有编译能力,转换后使用 Ninja 编译。

在编译过程中,kati 负责把既有的 Makefile、Android.mk 文件转换成 Ninja 文件。在 Android 8.0 以后,它与 Soong 一起,成为 Ninja 文件的两大来源。Kati 更像是 Google 过渡使用的一个工具,等所有 Android.mk 都被替换成 Android.bp 之后,Kati 有可能退出 Android 编译过程.

在单独使用时,它对普通的小项目还能勉强生效。面对复杂的、多嵌套的 Makefile 时,它往往无法支持,会出现各种各样的问题。当然,也可以理解为,它只为 Android 而设计。

kati 脚本和代码目录:/build/kati

3、blueprint

Blueprint 由 Go 语言编写,是生成、解析 Android.bp 的工具,是 Soong 的一部分。Soong 则是专为 Android 编译而设计的工具,Blueprint 只是解析文件的形式,而 Soong 则解释内容的含义。在 Android 编译最开始的准备阶段,会执行 build/soong/soong_ui.bash 进行环境准备。

对 blueprint 项目编译完成之后会在 out/soong/host/linux-x86/bin 目录下生成 soong 编译需要的 5 个执行文件(bpfix、bpfmt、bpmodify、microfatory 和 bpmodify)。 Soong 是与 Android 强关联的一个项目,而 Blueprint 则相对比较独立,可以单独编译、使用。

blueprint 代码目录:/build/blueprint

4、ninja

最开始,Ninja 是用于 Chromium 浏览器中,Android 在 SDK 7.0 中也引入了 Ninja。Ninja 是一个致力于速度的小型编译系统(类似于 Make),如果把其他编译系统比做高级语言的话,Ninja 就是汇编语言。通常使用 Kati 或 soong 把 makefile 转换成 Ninja files,然后用 Ninja 编译。

主要特点

  • 可以通过其他高级的编译系统生成其输入文件;
  • 它的设计就是为了更快的编译。

ninja 核心是由 C/C++ 编写的,同时有一部分辅助功能由 python 和 shell 实现。由于其开源性,所以可以利用 ninja 的开源代码进行各种个性化的编译定制。

从 Android 7.0 开始,编译时默认使用 Ninja。但是,Android 项目里是没有 .ninja 文件的。遵循 Ninja 的设计哲学,编译时,会先把 Makefile 通过 kati 转换成 .ninja 文件,然后使用 ninja 命令进行编译。这些 .ninja 文件,都产生在 out/ 目录下,共有三类:

  • 第一类:build-*.ninja 文件,通常非常大,几十到几百 MB。对 make 全编译,命名是build-<product_name>.ninja。如果 Makefile 发生修改,需要重新产生 Ninja 文件。

mm、mma 的 Ninja 文件,命名是 build-<product_name>-<path_to_Android.mk>.ninja。而 mmm、mmma 的 Ninja 文件,命名是 build-<product_name>-_<path_to_Android.mk>.ninja。

  • 第二类:combined-.ninja 文件。在使用了 Soong 后,除了 build-.ninja 之外,还会产生对应的 combined-.ninja,二者的内容相同。

这类是组合文件,是把 build-.ninja 和 out/soong/build.ninja 组合起来。所以,使用 Soong 后,combined-.ninja 是编译执行的真正入口。

  • 第三类:out/soong/build.ninja 文件,它是从所有的 Android.bp 转换过来的。

build-.ninja 是从所有的 Makefile,用 Kati 转换过来的,包括 build/core/.mk 和所有的 Android.mk。所以,在不使用 Soong 时,它是唯一入口。在使用了 Soong 以后,会新增源于 Android.bp 的 out/soong/build.ninja,所以需要 combined-*.ninja 来组合一下。

四、工具链关系

Android.mk 文件、Android.bp、kati、Soong、Blueprint 和 Ninja 之间的关系如下:

bash 复制代码
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 10.0 中,mk 文件通过 kati\ckati 编译生成 build-aosp_arm.ninja, bp 文件通过 blueprint-soong 解析编译生成为 build.ninja,这些 ninja 文件会合并成 combined-aosp_arm.ninja,最终通过 ninja 工具进行最终的编译。

随着 Google 的不停演进,make 的编译会最终退出历史舞台,kati\ckati 也会退出,最终全部切到 blueprint-soong 的编译。

相关推荐
Industio_触觉智能1 小时前
量产技巧之RK3588 Android12默认移除导航栏&状态栏
android·rk3588·开发板·核心板·瑞芯微·rk3588j
小馬佩德罗1 小时前
Android系统的问题分析笔记 - Android上的调试方式 bugreport
android·调试
VividnessYao1 小时前
Android Handler 消息机制
android
iReaShare2 小时前
如何将华为文件传输到电脑
android
火柴就是我2 小时前
每日见闻之Rust中 trait 的孤儿规则
android·rust
IT 前端 张3 小时前
uni-app在安卓设备上获取 (WIFI 【和】以太网) ip 和 MAC
android·tcp/ip·uni-app
iReaShare3 小时前
如何轻松将音乐从安卓设备传输到安卓设备
android
狂浪天涯3 小时前
Android 16 | Display Framework - 2 | Surface
android·操作系统