Android 源码构建维度

为什么Android源码要引入这样一套构建系统呢?里面涉及几个维度思考:

  • 编译核心:编译系统的核心,决定了整个项目的最核心编译规则,定义了编译流程的框架,源码在build/core/目录下

  • 模块维度:模块是编译系统的最小的目标单元。Android早期采用Android.mk,其中定义了一个模块的必要参数,使模块跟随平台编译。编译核心要让所有的模块全部include进来。

  • 产品维度:出现在build/target/、device/或vendor/目录中。 这部分的主要入口是AndroidProducts.mk文件,功能是指定一些产品独特的内容。 这些额外的组件,会随着编译前lunch PRODUCT的PRODUCT参数而改变。

  • 映像维度: Android 源码构建的最终目标是要生成各类映像文件,以便最后刷机使用

Android的编译核心目标

Android默认目标就是droid,droid目标的依赖如下:
Android Build 系统解析

Android 编译核心逻辑

Android Build 系统解析

这些规则定义在build/core/main.mk里面,主要逻辑包括:

  1. 定义编译目标product
  2. 加载config.mk来初始化相关变量,检测编译环境和目标环境
  3. 清除规则,清除out目录中的dex文件
  4. 加载build/croe/definitions.mk,定义了很多通用函数,供编译过程调
  5. 加载平台开发工具包 build/make/core/pdk_config.mk
  6. 加载系统中所有的Android.mk,最终会被存放到out/.module_paths/Android.mk.list
  7. Link 类型检查,校验Link
  8. 要为此产品生成的模块的基本列表由相应的产品定义文件指定,这些定义在"product_config.mk"中
  9. 运行时APEX库,并进行检查校验
  10. 将所有要安装的模块都保存在变量ALL_DEFAULT_INSTALLED_MODULES中,并且将build/core/Makefie文件加载进来。build/core/Makefie文件会根据要安装的模块生成system.img、super.img、boot.img和recovery.img等镜像文件的生成规则
  11. 定义编译的image目标
  12. 构建文件,然后将其打包成rom格式

Android编译核心文件

Android Build 系统解析

Android打包流程

Android Build 系统解析

System打包流程

BUILT_SYSTEMIMAGE 最终会把system.img编译到 out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img中。

BUILT_SYSTEMIMAGE 依赖于FULL_SYSTEMIMAGE_DEPS、INSTALLED_FILES_FILE和BUILD_IMAGE_SRCS,通过调用 函数build-systemimage-target 来编译systemimage,相关依赖如下所示:

  • BUILD_IMAGE_SRCS 在[/build/make/core/config.mk] 中定义,配置了build/make/tools/releasetools中的python脚本参与编译
    BUILD_IMAGE_SRCS := $(wildcard build/make/tools/releasetools/*.py)

  • INSTALLED_FILES_FILE 依赖的是文件$(PRODUCT_OUT)/installed-files.txt,这是已安装的文件列表,这些文件要打包到system.img中,他也依赖于FULL_SYSTEMIMAGE_DEPS

  • FULL_SYSTEMIMAGE_DEPS依赖于INTERNAL_SYSTEMIMAGE_FILES 和INTERNAL_USERIMAGES_DEPS,列出了制作system.img所需要的工具和制作system.img所需要的文件。

Android设置编译工具链

加载config.mk来初始化相关变量,检测编译环境和目标环境,加载clang/config.mk,配置一些编译的环境。

include build/make/core/config.mk

#加载out/soong/make_vars-aosp_arm.mk
include $(SOONG_MAKEVARS_MK)

#加载clang编译的一些配置
include $(BUILD_SYSTEM)/clang/config.mk

Soong overview

Android Build 系统解析
使用方法和以前一样。先引入build/envsetup,sh,然后执行m/mm/mmm等命令。只不过现在的m/mm/mmm命令将调用Soong中的对应工具。

Soong将把.bp文件交给blueprint工具集来处理。blueprint工具集是用go语言写的。官方文档对它的描述是:a meta-build system。输入为.bp文件。输出为.ninja文件

Soong把.mk/Makefile文件交给kati/ckati工具来处理。kati是go语言写的,而ckati是c++写的。kati官方文档对它的描述是:kati is an experimental GNU make clone。也就是说,kati是对等make命令的。只不过kati并不执行具体的编译工作,而是生成ninja文件。

ninja是一个神奇的东西,它是忍者桃太郎的意思。ninja本身不是编译器,它是去调用具体编译器的工具。真正的编译工作还是由编译器来完成,比如gcc,clang,java等。ninja读取的是.ninja结尾的编译配置文件,然后调起对应的编译器。

Make入口 soong_ui.bash

envsetup.sh主要是用于初始化shell环境,使其支持android build系统的特有命令:croot、mgrep、cgrep、m、mm等,和build系统相关的主要是m、mm、mmm、mma、ma、make,尤其是make

当我们执行make,在envsetup.sh初始化后的shell环境中,执行的是function make函数
function make()
{
_wrap_build ( g e t m a k e c o m m a n d " (get_make_command " (getmakecommand"@") “[email protected]
}

这里判断当前make是在build系统根目录下,则执行build/soong/soong_ui.bash --make-mode

注意:这里是echo,使用echo作为get_make_command返回值,我们调用的是make -j8,

此时@就是-j8,经过shell展开处理后_wrap_build(get_make_command "@") "@"展开成了build/soong/soong_ui.bash --make-mode -j8

Android10.0上是通过soong执行编译构建,这里执行make命令时,main.mk文件把一些环境变量和目标都配置好后,会执行envsetup.sh中的make()进行编译。
如果找到“build/soong/soong_ui.bash”,就使用soong_ui.bash 来进行编译,否则使用原始的make命令进行编译。
Android Build 系统解析

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

编译步骤如下:

  1. runMakeProductConfig 主要配置编译参数

  2. runSoong 对工具进行编译,编译出blueprint等编译工具, 把*.bp 编译成 out/soong/build.ninja

/.minibootstrap/build.ninja

  • Run minibp to generate .bootstrap/build.ninja (Primary stage) - Run minibp to generate .minibootstrap/build.ninja.in
    /.bootstrap/build.ninja
  • Build any bootstrap_go_binary rules and dependencies – usually the primary builder and any build or runtime dependencies. - Run the primary builder to generate build.ninja
  1. runKatiBuild, 加载 build/make/core/main.mk, 搜集所有的Android.mk文件生成ninja文件:out/build-aosp_arm.ninja

  2. runKatiPackage, 加载build/make/packaging/main.mk, 编译生成out/build-aosp_arm-package.ninja

  3. createCombinedBuildNinjaFile,将out/soong/build.ninja 、out/build-aosp_arm.ninja和out/build-aosp_arm-package.ninja, 合成为out/combined-aosp_arm.ninja

  4. runNinja,运行Ninja命令, 解析combined-aosp_arm.ninja,执行编译过程

参考:
https://mp.weixin.qq.com/s/pMg0TxGlqAWmZZ5TW-CzWA
https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MjM5NDk5ODQwNA==&action=getalbum&album_id=1552818877435265027&scene=173&from_msgid=2652469359&from_itemidx=1&count=3#wechat_redirect

https://blog.csdn.net/Innost/article/details/103286516
https://blog.csdn.net/Innost/article/details/103519211

相关文章: