Ninja,Kati,Soong等知识深入扫盲

Ninja介绍

最开始,Ninja 是用于Chromium 浏览器中,Android 在7.0 中也引入了Ninja,因为随着Android系统和应用程序的增长,这种构建方式变得越来越慢,尤其是在大型项目中。为了解决这个问题,Google开始引入新的构建系统来提高编译速度和效率。
Ninja是一个小型的、专注于速度的构建系统,最初由Google的程序员Chris Manson开发,最初用于加速Chrome浏览器的构建过程。Ninja的设计思路简化构建过程,通过精确指定输入和输出关系,实现快速增量构建。

与Make相比,Ninja舍弃了各种高级功能来实现快速的增量编译。Make具有各种高级功能,比如函数、内置规则,而Ninja则专注于速度。Ninja的构建文件是可读的,但更多场合下,是由其他构建系统的工程文件自动生成的。

Ninja被用于构建Google Chrome、部分Android系统、LLVM等项目。由于CMake支持Ninja后端,CMake可以生成Ninja构建文件,从而利用Ninja的高效构建能力。
ninja的官网:https://ninja-build.org/manual.html

Ninja

Ninja is a small build system with a focus on speed. It differs from other build systems in two major respects: it is designed to have its input files generated by a higher-level build system, and it is designed to run builds as fast as possible.

Why yet another build system?

Where other build systems are high-level languages Ninja aims to be an assembler.

Ninja build files are human-readable but not especially convenient to write by hand. (See the generated build file used to build Ninja itself.) These constrained build files allow Ninja to evaluate incremental builds quickly.
Should you use Ninja?

Ninja's low-level approach makes it perfect for embedding into more featureful build systems; see a list of existing tools. Ninja is used to build Google Chrome, parts of Android, LLVM, and can be used in many other projects due to CMake's Ninja backend.

See the manual for more: philosophical background, whether and how you can use Ninja for your project, platform support, and details about the language semantics.

Makefile与Ninja的对比

优势对比
Ninja 和 Make 都是构建系统,用于自动化编译和构建软件项目。Ninja 是在 Make 的基础上发展起来的,它旨在解决 Make 在某些方面的局限性,特别是在大型项目中的性能问题。

以下是 Ninja 相比 Make 的一些优势:

速度: Ninja 的主要优势是速度快。它在设计时就注重减少磁盘 I/O 和提高构建速度。Ninja 通过预先计算构建依赖关系,并在构建文件中明确指定,从而避免了 Make 在构建过程中重复扫描源代码文件的开销。这个个人理解有点以硬盘文件空间换cpu速度。

依赖关系: Ninja 的依赖关系更加明确和静态。它不依赖于文件的时间戳来确定是否需要重新构建,而是使用文件内容的哈希值,这减少了在构建过程中的不确定性和不必要的构建。

构建文件: Ninja 的构建文件(.ninja 文件)通常由其他工具(如 GN 或 CMake)生成,这使得构建文件的维护和管理更加一致和简单。而 Makefile 通常需要手工编写,容易出错且难以维护。

简洁性: Ninja 的构建文件更加简洁,因为它避免了 Makefile 中常见的复杂逻辑和条件判断。这使得 Ninja 文件更容易理解和修改。

可靠性: Ninja 在遇到错误时会立即停止构建,而不是尝试继续执行其他任务。这有助于更快地发现和解决问题。

工具链无关性: Ninja 不关心底层的编译器或工具链,它只负责调度构建任务。这使得 Ninja 可以与多种编译器和工具链一起使用,而 Make 可能需要为不同的编译器或工具链编写不同的 Makefile。

编译文件对比:
一般make构建时候,使用的大部分都是Android.mk或Makefile文件进行编译,但是ninja构建时候都是需要使用.ninja文件。
但是在看ninja介绍时候

Ninja build files are human-readable but not especially convenient to write by hand. 

上面注释Ninja也大概可以看出,ninja是我们人直接可以看得懂的,但是大部分情况下不需要手写的,那么ninja文件是桌面来的呢?
本身平时开发中依然编译目标时候,使用的也是Android.mk文件和以前make构建时候没啥变化,接下来就是需要我们的装机工具来帮忙从Android.mk生成对应ninja文件。

Kati工具

在从Make过渡到Ninja的过程中,Google开发了Kati工具,用于将Android.mk文件转换为Ninja可以理解的构建文件。这样,现有的Android.mk文件可以被重用于新的构建系统,而不需要立即迁移到新的格式。

这里给出一个简单的kati工具使用的流程,便于更好地理解Kati工具:
寻找工具文件:

test@test:~/aosp$ cd prebuilts/
test@test:~/aosp/prebuilts$ find -name ckati
./build-tools/linux_musl-x86/asan/bin/ckati
./build-tools/linux_musl-x86/bin/ckati
./build-tools/darwin-x86/bin/ckati
./build-tools/linux-x86/asan/bin/ckati
./build-tools/linux-x86/bin/ckati

我们用./build-tools/linux-x86/bin/ckati。

假设你有一个简单的 Android.mk 文件,它定义了一个模块的编译规则,如下所示:

include $(CLEAR_VARS)
LOCAL_MODULE := my_module
LOCAL_SRC_FILES := my_source.c
include $(BUILD_SHARED_LIBRARY)

这个 Android.mk 文件告诉构建系统如何编译一个共享库 my_module,它由 my_source.c 源文件构建而来。使用 Kati 转换这个过程如下:

   $cd path/to/your/module
    $ckati --ninja

这将生成一个 build.ninja 文件,内容类似于:

rule cc
  command = gcc -c $cflags -o $out $in
  description = COMPILE
 
build my_module.o: cc my_source.c
build my_module: link my_module.o

然后,你可以使用 Ninja 来构建这个模块:

$ninja -f build.ninja

Soong工具构建系统引入

从Android 7.0(Nougat)开始,引入了Soong构建系统,它使用Android.bp文件来定义构建规则,并生成Ninja构建文件。在Android 8.0(Oreo)中,Google进一步引入了Android.bp文件和Soong构建系统。Android.bp文件是一种更简洁、更易于维护的构建脚本格式。Soong是一个新的构建引擎,它使用Android.bp文件来生成Ninja构建文件。

这里给出一个简单的kati工具使用的流程,便于更好地理解Soong工具:

假设你有一个简单的 Android.bp 文件,它定义了一个 C/C++ 库的构建规则,如下所示:

cc_library_shared {
    name: "my_library",
    srcs: ["src/my_library.c"],
    shared_libs: ["liblog"],
    export_include_dirs: ["include"],
}

这个 Android.bp 文件告诉构建系统如何编译一个共享库 my_library,它由 src/my_library.c 源文件构建而来,并包含 liblog 库。

在 Android 构建环境中,通常不需要直接调用 Soong 命令,因为构建脚本会自动化这个过程。这里为了方便理解,使用手动方式触发 Soong 的构建过程,使用以下命令:

source build/envsetup.sh
lunch XXX-target
out/soong/.bootstrap/bin/soong_build --make-mode <target-moudle>

这个命令会执行 Soong,生成 out/soong/build.ninja 文件,然后 Ninja 会使用这个文件来编译项目,使用 Ninja 来构建这个模块:

$ninja -f build.ninja

工具链关系

Android.mk、Android.bp、Soong、Blueprint、Ninja 简单的方式表达这几个概念之间的作用关系

Android.bp --> Blueprint --> Soong --> Ninja

Makefile or Android.mk --> kati --> Ninja

Kati 将 Android.mk 转换为 Ninja 文件。
Soong 解析 Android.bp 文件并生成 Ninja 文件。
Ninja 读取生成的 Ninja 文件,并执行构建任务。
在这里插入图片描述build-sdk_phone_x86_64.ninja文件大小才不到1G
在这里插入图片描述
但是out/soong/build.ninja大小大于10G,相差十几倍
在这里插入图片描述看看combined-sdk_phone_x86_64.ninja


builddir = out
pool highmem_pool
 depth = 5
subninja out/build-sdk_phone_x86_64.ninja
subninja out/build-sdk_phone_x86_64-package.ninja
subninja out/soong/build.ninja

可以看到它主要是依赖上面两个用subninja来声明依赖,并不是说把两个文件大小进行合并。

Ninja命令编译

注意:大家一定要使用aosp系统源码自带的ninja版本的bin文件,切勿使用ubunutu版本安装的,因为会有版本差异等问题。

寻找ninja命令位置

test@test:~/aosp/prebuilts$ find -name ninja
./build-tools/linux_musl-x86/asan/bin/ninja
./build-tools/linux_musl-x86/bin/ninja
./build-tools/darwin-x86/bin/ninja
./build-tools/linux-x86/asan/bin/ninja
./build-tools/linux-x86/bin/ninja

可以看看相关的ninja命令的帮助

test@test:~/aosp$ ./prebuilts/build-tools/linux-x86/bin/ninja -h
usage: ninja [options] [targets...]

if targets are unspecified, builds the 'default' target (see manual).

options:
  --version      print ninja version ("1.9.0.git")
  -v, --verbose  show all command lines while building
  --quiet        don't show progress status, just command output

  -C DIR   change to DIR before doing anything else
  -f FILE  specify input build file [default=build.ninja]

  -j N     run N jobs in parallel (0 means infinity) [default=22 on this system]
  -k N     keep going until N jobs fail (0 means infinity) [default=1]
  -l N     do not start new jobs if the load average is greater than N
  -n       dry run (don't run commands but act like they succeeded)

  -d MODE  enable debugging (use '-d list' to list modes)
  -t TOOL  run a subtool (use '-t list' to list subtools)
    terminates toplevel options; further flags are passed to the tool
  -o FLAG  adjust options (use '-o list' to list options)
  -w FLAG  adjust warnings (use '-w list' to list warnings)

  --frontend COMMAND    execute COMMAND and pass serialized build output to it
  --frontend_file FILE  write serialized build output to FILE

参数比较多,比较常用的就是 -f 用来指定相关的ninja文件,比如aosp想要用ninja来构建system_server

操作方式如下:

test@test:~/aosp$ ./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-sdk_phone_x86_64.ninja services

[78/78] Install out/target/product/emulator_x86_64/system/framework/services.jar

也可以考虑使用软链接ninja文件,然后省略-f参数:

test@test:~/aosp$ ln -s out/combined-sdk_phone_x86_64.ninja build.ninja #软件到aosp根目录

test@test:~/aosp$ ./prebuilts/build-tools/linux-x86/bin/ninja services
[78/78] Install out/target/product/emulator_x86_64/system/framework/services.jar

还有就是-t参数,可以ninja -t list来查看有哪些subtools

test@test:~/aosp$ ./prebuilts/build-tools/linux-x86/bin/ninja -t list
ninja subtools:
    browse  browse dependency graph in a web browser
     clean  clean built files
  commands  list all commands required to rebuild given targets
      deps  show dependencies stored in the deps log
     graph  output graphviz dot file for targets
    inputs  show all (recursive) inputs for a target
      path  find dependency path between two targets
     paths  find all dependency paths between two targets
     query  show inputs/outputs for a path
   targets  list targets by their rule or depth in the DAG
    compdb  dump JSON compilation database to stdout
 recompact  recompacts ninja-internal data structures

总结及感悟

在以Ninja在实际编译中替换 Makefile 以后,Android在编译时更快了一些。 不过,在首次生成、或重新生成Ninja文件时,往往额外耗时数分钟,反而比原先使用Makefile更慢了。

这个也就可以解释很多学员朋友都反馈自己电脑配置一般(主要cpu和内存),第一次从0开始编译发现速度很慢,经常发现生成ninja时候都过去不去oom退出了。
上面看到ninja文件大小相信大家也可以大概理解,要把所有系统中的Android.mk,Android.bp进行转换,生成巨大体积的ninja文件。
由于Ninja的把编译流程集中到了一个文件,并且提供了一些工具命令。 所以编译信息的提取、编译依赖的分析,变得更加方便了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值