Ninja简介-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编译演进过程:

     1)Android7.0之前 使用GNU Make

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

     3)Android8.0 默认打开Android.bp

     4)Android9.0 强制使用Android.bp

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

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

Ninja是一个注重速度的小型构建系统。它与其他构建系统在两个主要方面不同:它被设计为使其输入文件由更高级别的构建系统生成,并且被设计为尽可能快地运行构建。

    Android系统的编译历程:

2 Make与ninja的对比
    在传统的C/C++项目中,通常采用make系统使用Makefile来进行整个项目的编译构建,Makefile指定的编译依赖规则会使编译流程简单,但是make的依赖大而且复杂,在大型项目编译时,使用的模块越来越多,Makefile组织的项目编译时间越来越长,这个对于编译效率来说是一个极大的浪费。

Ninja是由Google员工Evan Martin 开发的小型构建系统。Ninja注重速度,它在两个主要方面与其他构建系统有所不同:Ninja被设计为使其输入文件由更高级别的构建系统生成,并且其被设计为尽可能快地运行构建。

    本质上,Ninja旨在替换Make,这在执行增量(或无操作)构建时很慢。这可能会大大降低开发人员在大型项目上的工作速度,例如Google Chrome将40,000个输入文件编译为单个可执行文件。实际上,谷歌浏览器是忍者的主要用户和动机。它也用于构建Android ,并且被大多数从事LLVM的开发人员所使用。

    与Make相比,Ninja缺少诸如字符串操作之类的功能,因为Ninja生成文件不是要手工编写的。相反,应使用“生成生成器”生成Ninja生成文件。Gyp,CMake,Meson和gn 是流行的构建管理软件工具,它们支持为Ninja创建构建文件。

 

Ninja开发时,认为make由以下几点导致编译慢:

隐式规则,make包含很多默认

变量计算,比如编译参与应该如何计算出来

依赖对象计算

 

ninja相对于make增加了下面这些功能:

如果构建命令发生变化,那么这个构建也会重新执行。

所依赖的目录在构建之前都已经创建了,如果不是这样的话,我们执行命令之前都要去生成目录。

每条构建规则,除了执行命令之外,还允许有一个描述,真正执行打印这个描述而不是实际执行命令。

每条规则的输出都是buffered的,也就是说并行编译,输入内容不会被搅和在一起。

 

    针对这点所以基本上可以认为ninja就是make的最最精简版。

    Make编译使用的文件名为Makefile、makefile或者以.make、.mk结尾的文件,Ninja的文件名一般为build.ninja或者以.ninja结尾的文件。


3 ninja的用法
3.1 ninja代码位置
    Android自带ninja,ninja路径:
 

prebuilts/build-tools/darwin-x86/bin/ninja
prebuilts/build-tools/linux-x86/bin/ninja
prebuilts/build-tools/linux-x86/asan/bin/ninja

3.2 命令的用法

    执行ninja -h 后,可以得到ninja的使用帮助说明

 我们在编译时,常用的是-t参数。我们执行一下ninja -t list会得到相应的指令说明:

例如 ninja -t clean 用来清除编译中间文件,相比make clean减少了研发人员的开发过程。

指令说明:

ninja subtools:
 
browse        # 在浏览器中浏览依赖关系图。(默认会在 8080 端口启动一个基于python的http服务)
clean         # 清除构建生成的文件
commands      # 罗列重新构建制定目标所需的所有命令
deps          # 显示存储在deps日志中的依赖关系
graph         # 为指定目标生成 graphviz dot 文件。
              #  如 ninja -t graph all |dot -Tpng -ograph.png
query         # 显示一个路径的inputs/outputs
targets       # 通过DAG中rule或depth罗列target
compdb        # dump JSON兼容的数据库到标准输出
recompact     # 重新紧凑化ninja内部数据结构

4 ninja的实践

4.1 下载ninja

下载地址:

git clone https://github.com/ninja-build/ninja.git

4.2 编译ninja

cd ninja
./configure.py --bootstrap #在ninja目录中执行

4.3 安装ninja
    编译结束后,会在ninja目录中生成ninja的可执行程序ninja。可以直接将ninja程序拷贝到/usr/bin中。cp ./ninja /usr/bin #在ninja目录中执行

    现在就可以在任意位置使用ninja了。

4.4 ninja实践
    1)mkdir test

    2)vim test/main.c

   填入代码内容:

#include <stdio.h>
#include <stdlib.h>
int main() {
  printf("This is my first Ninja Project!\n");
  return 0;
}

3)配置build.ninja

      vim build.ninja

    填入内容:

cc = g++
cflags = -Wall
 
rule cc
  command = gcc $cflags -c $in -o $out
  description = compile .cc
 
build foo.o: cc foo.c

 4)编译:

cd test
ninja

5 ninja编译流程

5.1 AOSP编译过程

5.2.ninja生成过程
    在编译过程中,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

    最终由ninja -t 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

6 总结

    Ninja的诞生,主要是为了提升编译速度,Ninja中去除了变量的计算,没有默认规则, 依赖必须显式声明,从而提升编译速度。基本上可以认为ninja就是make的最最精简版。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值