编译系统入门篇-Android10.0编译系统(一)

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

Android系统架构
Android是怎么启动的
Android 10.0系统启动之init进程
Android10.0系统启动之Zygote进程
Android 10.0 系统启动之SystemServer进程
Android 10.0 系统服务之ActivityMnagerService
Android10.0系统启动之Launcher(桌面)启动流程
Android10.0应用进程创建过程以及Zygote的fork流程
Android 10.0 PackageManagerService(一)工作原理及启动流程
Android 10.0 PackageManagerService(二)权限扫描
Android 10.0 PackageManagerService(三)APK扫描
Android 10.0 PackageManagerService(四)APK安装流程
《日志系统篇》

Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现​
《Binder通信原理》:

Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
Android10.0 Binder通信原理(二)-Binder入门篇
Android10.0 Binder通信原理(三)-ServiceManager篇
Android10.0 Binder通信原理(四)-Native-C\C++实例分析
Android10.0 Binder通信原理(五)-Binder驱动分析
Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
Android10.0 Binder通信原理(七)-Framework binder示例
Android10.0 Binder通信原理(八)-Framework层分析
Android10.0 Binder通信原理(九)-AIDL Binder示例
Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
Android10.0 Binder通信原理(十一)-Binder总结

《HwBinder通信原理》

HwBinder入门篇-Android10.0 HwBinder通信原理(一)
 HIDL详解-Android10.0 HwBinder通信原理(二)
HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
HwServiceManager篇-Android10.0 HwBinder通信原理(五)
Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
Native层HIDL服务的获取原理-Android10.0 HwBinder通信原理(七)
JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)
JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)
HwBinder驱动篇-Android10.0 HwBinder通信原理(十)
HwBinder原理总结-Android10.0 HwBinder通信原理(十一)
《编译原理》

编译系统入门篇-Android10.0编译系统(一)
编译环境初始化-Android10.0编译系统(二)
make编译过程-Android10.0编译系统(三)
Image打包流程-Android10.0编译系统(四
Kati详解-Android10.0编译系统(五)
Blueprint简介-Android10.0编译系统(六)
Blueprint代码详细分析-Android10.0编译系统(七)
Android.bp 语法浅析-Android10.0编译系统(八)
Ninja简介-Android10.0编译系统(九)
Ninja提升编译速度的方法-Android10.0编译系统(十)
Android10.0编译系统(十一)

 
1 概述
  在 Android 7.0 之前,Android 编译系统使用 GNU Make 描述和shell来构建编译规则,模块定义都使用Android.mk进行定义,Android.mk的本质就是Makefile,但是随着Android的工程越来越大,模块越来越多,Makefile组织的项目编译时间越来越长。这样下去Google工程师觉得不行,得要优化。

  因此,在Android7.0开始,Google采用ninja来代取代之前使用的make,由于之前的Android.mk数据实在巨大,因此Google加入了一个kati工具,用于将Android.mk转换成ninja的构建规则文件buildxxx.ninja,再使用ninja来进行构建工作。

  ninja的网址:https://ninja-build.org

  编译速度快了一些,但是既然要干, 那就干个大的,最终目标要把make都取代,于是从Android8.0开始,Google为了进一步淘汰Makefile,因此引入了Android.bp文件来替换之前的Android.mk。

  Android.bp只是一个纯粹的配置文件,不包括分支、循环语句等控制流程,本质上就是一个json配置文件。Android.bp  通过Blueprint+soong转换成ninja的构建规则文件build.ninja,再使用ninja来进行构建工作。

  Android10.0上,mk和bp编译的列表可以从 \out\.module_paths中的Android.bp.list、Android.mk.list中看到,Android10.0还有400多个mk文件没有被替换完,Google任重道远。

  Android编译演进过程:

Android7.0之前 使用GNU Make

Android7.0 引入ninja、kati、Android.bp和soong构建系统

Android8.0 默认打开Android.bp

Android9.0 强制使用Android.bp

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

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

  Android系统的编译历程:

 

2 编译流程

2.1 编译构成

  Android的编译目录在/build 中,看一下Android 10源码中的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

  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

out/combined-aosp_arm.ninja内容如下所示:
 

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

2.2 编译步骤
  source build/envsetup.sh

  lunch aosp_arm-eng // 或者 m PRODUCT-aosp_x86_64-eng ,Android10.0不一定需要lunch命令

  make -j8      //编译模块也可以直接用 m libart

    Android10.0编译步骤如下图所示:

3 编译环境初始化
3.1 envsetup说明
  编译的第一步需要初始化一下环境变量,通过以下命令完成:

 source build/envsetup.sh
  这里的envsetup.sh被link到了 build/make/envsetup.sh

  envsetup.sh 主要做了下面几个事情:

 在source build/envsetup.sh后,输入hmm可以看到envsetup支持的一些接口:

3.2 Lunch 说明
  环境变量初始化完成后,我们需要选择一个编译目标。lunch 主要作用是根据用户输入或者选择的产品名来设置与具体产品相关的环境变量。

  如果你不知道想要编译的目标是什么,直接执行一个lunch命令,会列出所有的目标,直接回车,会默认使用aosp_arm-eng这个目标。

执行命令:lunch 1, 可以看到配置的一些环境变量

 

4.Make 说明
  执行完lunch命令后,就可以使用make命令来执行编译Build。

  Android10.0上是通过soong执行编译构建,这里执行make命令时,main.mk文件把一些环境变量和目标都配置好后,会执行envsetup.sh中的make()进行编译。

  如果找到“build/soong/soong_ui.bash”,就使用soong_ui.bash 来进行编译,否则使用原始的make命令进行编译。

function make()
{
    _wrap_build $(get_make_command "$@") "$@"
}
function get_make_command()
{
    # If we're in the top of an Android tree, use soong_ui.bash instead of make
    if [ -f build/soong/soong_ui.bash ]; then
        # Always use the real make if -C is passed in
        for arg in "$@"; do
            if [[ $arg == -C* ]]; then
                echo command make
                return
            fi
        done
        echo build/soong/soong_ui.bash --make-mode
    else
        echo command make
    fi
}

配置一些资源环境,得到一些函数命令,例如:soong_build_go,最终回退到根目录,执行out/soong_ui --make-mode进行真正的构建

soong_build_go soong_ui android/soong/cmd/soong_ui  是通过编译

android/soong/cmd/soong_ui/main.go来编译生成soong_ui。
 

[build/soong/soong_ui.bash]
# Save the current PWD for use in soong_ui
export ORIGINAL_PWD=${PWD}
export TOP=$(gettop)
source ${TOP}/build/soong/scripts/microfactory.bash
 
soong_build_go soong_ui android/soong/cmd/soong_ui
 
cd ${TOP}
exec "$(getoutdir)/soong_ui" "$@"
 
“echo build/soong/soong_ui.bash --make-mode ”

最终会执行 exec  out/soong_ui  --make-mode 进行编译

soong的编译过程如下图所示:

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

  main.mk的包含关系如下图所示:

 

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

  Android10.0编译工具链:

soong\kati\blueprint\ninja 
5.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

 

5.2.kati说明
  kati是一个基于Makefile来生成ninja.build的小项目。主要用于把Makefiel转成成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

 

5.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

 

5.4.ninja说明

  最开始,Ninja 是用于Chromium 浏览器中,Android 在SDK 7.0 中也引入了Ninja。

  Ninja是一个致力于速度的小型编译系统(类似于Make),如果把其他编译系统比做高级语言的话,Ninja就是汇编语言。通常使用Kati或soong把makefile转换成Ninja files,然后用Ninja编译。

  主要两个特点:

  1)可以通过其他高级的编译系统生成其输入文件;

  2)它的设计就是为了更快的编译;

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

  从Android 7开始,编译时默认使用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来组合一下。

 

6.工具链的关系
  Android.mk文件、Android.bp、kati、Soong、Blueprint、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文件才是真正直接控制源码编译的工具。

 

7.总结
  Android10.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的编译。

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值