Android 编译系统--09:Ninja简介

本文转载自:Ninja简介-Android10.0编译系统(九)

本文基于Android 10.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来进行构建工作。

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

(1)Android编译演进过程

  • 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)Android系统的编译历程

编译系统9-1.PNG

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创建构建文件。

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

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

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

  • 依赖对象计算。

(2)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的使用帮助说明。

编译系统9-2.png

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

编译系统9-3.png

例如: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编译过程

编译系统9-4.png

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的最最精简版。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容