Android build子系统(01)Ninja构建系统解读

说明:本文将解读Ninja构建系统,这是当前Android Framework中广泛使用的构建工具。我们将从Ninja的起源和背景信息开始,逐步解读Ninja的优势和核心原理,并探讨其一般使用场景。然后介绍其在Android Framework中的应用及相关工具:kati、soong、gn等,最后介绍下如何自行构建一个Ninja编译系统,以便于对Ninja有一个完整的了解。


1 Ninja基本内容解读

1.1 什么是Ninja?

Ninja是一个小型的、专注于速度的构建系统,最初由Google的程序员Chris Manson开发,最初用于加速Chrome浏览器的构建过程。Ninja的设计哲学是简化构建过程,通过精确指定输入和输出关系,实现快速增量构建。Ninja的首次使用是在开源的Chromium浏览器项目中,该项目拥有超过30,000个源文件,Ninja能够在不到一秒的时间内开始构建过程,相较于其他构建系统有显著的速度优势。

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

Ninja被用于构建Google Chrome、部分Android系统、LLVM等项目。由于CMake支持Ninja后端,CMake可以生成Ninja构建文件,从而利用Ninja的高效构建能力。

总之,Ninja是一个快速、轻量级的构建系统,专注于增量构建,常用于大型项目。

1.2 Ninja的核心原理解读

Ninja的核心原理基于构建文件中定义的规则和依赖关系,通过构建图(依赖图)来确定需要重新构建的目标。Ninja使用简单的文件时间戳比较来实现增量构建,避免了不必要的编译过程。总结下,它的核心原理主要包含以下几个方面:

  • 依赖图: Ninja构建过程基于一个明确的依赖图,这个依赖图定义了项目中所有文件的依赖关系。每个节点代表一个文件或一个构建命令,边代表依赖关系。Ninja在构建前会构建这个依赖图,并在构建时只执行那些受影响的节点。
  • 构建文件: Ninja使用.ninja文件作为输入,这些文件包含了构建规则和目标。这些规则定义了如何从输入文件生成输出文件。.ninja文件通常由其他工具(如GN或CMake)生成。
  • 增量构建: 只有当输入文件发生变化时,Ninja才会重新构建目标。它通过比较文件的时间戳来确定哪些文件需要更新。
  • 并行构建: Ninja能够并行执行多个构建任务,以充分利用多核处理器的能力。它会智能地调度任务,以最大化并行度并减少构建时间。
  • 避免冗余: Ninja的设计避免了不必要的工作。例如,它不会在构建过程中重新扫描依赖关系,因为这些信息已经在构建文件中明确指定。
  • 简洁性: Ninja的构建文件(.ninja文件)是简洁的,专注于构建逻辑,不包含条件逻辑或循环。这使得构建文件易于理解和维护。
  • 可靠性: Ninja在构建过程中会捕获错误并立即停止,这样可以避免无效的构建尝试。
  • 工具链无关性: Ninja本身不关心底层的编译器或工具链,它只负责调度构建任务。这使得Ninja可以与多种编译器和工具链一起使用。
  • 跨平台: Ninja可以在Windows、Linux和macOS等多种操作系统上运行,这使得它适用于跨平台项目。
  • 性能: Ninja的性能非常出色,尤其是在大型项目中。它能够快速地开始构建过程,并在构建过程中保持高效率。

Ninja的核心原理是提供一个简单、快速、可靠的构建系统,它通过优化构建过程和利用现代硬件的优势来实现这一目标。

1.3 Ninja相比于make的优势

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

  • 速度: Ninja 的主要优势是速度快。它在设计时就注重减少磁盘 I/O 和提高构建速度。Ninja 通过预先计算构建依赖关系,并在构建文件中明确指定,从而避免了 Make 在构建过程中重复扫描源代码文件的开销。
  • 并行构建: Ninja 能够更有效地利用多核处理器进行并行构建。它默认就会并行执行构建任务,而 Make 需要显式地通过 -j 选项来指定并行构建的作业数。
  • 依赖关系: Ninja 的依赖关系更加明确和静态。它不依赖于文件的时间戳来确定是否需要重新构建,而是使用文件内容的哈希值,这减少了在构建过程中的不确定性和不必要的构建。
  • 构建文件: Ninja 的构建文件(.ninja 文件)通常由其他工具(如 GN 或 CMake)生成,这使得构建文件的维护和管理更加一致和简单。而 Makefile 通常需要手工编写,容易出错且难以维护。
  • 简洁性: Ninja 的构建文件更加简洁,因为它避免了 Makefile 中常见的复杂逻辑和条件判断。这使得 Ninja 文件更容易理解和修改。
  • 可靠性: Ninja 在遇到错误时会立即停止构建,而不是尝试继续执行其他任务。这有助于更快地发现和解决问题。
  • 跨平台: Ninja 支持跨平台构建,可以在 Windows、Linux 和 macOS 上运行,而 Make 起源于 Unix 系统,虽然也有跨平台的支持,但在某些平台上可能需要额外的配置。
  • 工具链无关性: Ninja 不关心底层的编译器或工具链,它只负责调度构建任务。这使得 Ninja 可以与多种编译器和工具链一起使用,而 Make 可能需要为不同的编译器或工具链编写不同的 Makefile。
  • 一致性: Ninja 通过生成的构建文件来执行构建,这使得构建过程更加一致,不受环境变化的影响。而 Makefile 可能会受到当前 shell 环境的影响。
  • 性能: Ninja 在大型项目中的性能优势尤为明显,因为它能够更快地启动构建过程,并且在增量构建时更加高效。

总的来说,Ninja 通过优化构建过程和利用现代硬件的优势,提供了一种更快速、更可靠、更易于维护的构建解决方案。

1.4 Ninja的安装

ubuntu上可以直接安装:

$sudo apt install ninja-build

1.5 Ninja的一般使用场景

以下是 Ninja 的一般使用场景:

  • 跨平台构建:Ninja 支持在 Windows、Linux 和 macOS 等多种操作系统上运行,适用于跨平台项目构建。
  • 大型项目构建:Ninja 特别适合于大型项目,如 Chromium、LLVM 等,这些项目包含成千上万个源文件,Ninja 通过并行编译显著缩短构建时间。
  • 与现代构建系统配合:Ninja 常与 CMake 或 Meson 等现代构建系统配合使用,生成高效的构建文件。
  • 持续集成/持续部署(CI/CD):在 CI/CD 系统中,Ninja 的快速构建能力有助于缩短反馈循环时间,提高构建和测试的效率。
  • 需要快速迭代的场景:在开发过程中,如果需要频繁编译,Ninja 可以提供快速的反馈循环,使得开发者可以更快地进行代码迭代。
  • 自定义构建规则:Ninja 允许开发者自定义构建规则,适用于需要特殊构建逻辑的项目。
  • 与Android NDK配合:Android NDK 默认使用 Ninja 进行原生库的构建,因此在 Android 原生应用开发中,Ninja 是一个重要的工具。
  • Bazel 构建工具:Google 的 Bazel 构建工具虽然有自己的内部构建系统,但也可以配置为使用 Ninja 提高性能。

Ninja 的核心优势在于其构建速度和并行编译能力,这使得它成为许多大型和复杂项目的理想选择。

2 Ninja在Android Framework中的应用

Ninja适用于需要快速构建的大型项目,尤其是在C/C++代码编译方面表现出色。在Android Framework的构建中,Ninja主要用于编译原生代码,同时也支持Java/Kotlin代码的编译。

随着Android系统的不断演进,从Android 7.0(Nougat)开始引入了Soong构建系统,它使用Android.bp文件来定义构建规则,并生成Ninja文件,然后由Ninja执行实际的编译和链接任务。

2.1 为什么要引入ninja?

实际上在Android 7.0(Nougat)之前,Android系统主要使用Makefile和Android.mk文件来描述构建过程。这些文件定义了如何编译和链接模块,并通过调用make命令来执行构建任务。

随着Android系统和应用程序的增长,这种构建方式变得越来越慢,尤其是在大型项目中。为了解决这个问题,Google开始引入新的构建系统来提高编译速度和效率。

2.2 过渡期工具:Kati工具

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

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

假设你有一个简单的 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 cccommand = gcc -c $cflags -o $out $indescription = COMPILEbuild my_module.o: cc my_source.c
build my_module: link my_module.o

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

$ninja -f build.ninja

2.3 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

2.4 GN工具的引入

GN(Generate Ninja)是一个由Google开发的元构建系统,它用于生成Ninja构建文件,这些文件随后由Ninja构建系统使用来编译项目。GN在Android系统中的使用是逐步引入的。

GN在Android系统中的引入最开始主要是为了改善Chromium项目的构建性能。Chromium是Google Chrome浏览器的开源项目,它有着庞大的代码库。GN的设计目标是减少构建时间,尤其是在大型项目中。GN通过并行构建和优化依赖关系来提高构建速度。

从Android 8.0(Oreo)开始,GN的使用更加广泛,并且随着Android版本的更新,GN和Ninja的集成逐渐深入到Android的构建系统中。GN的主要优势如下:

  • 速度:GN生成的Ninja文件能够快速执行构建任务,尤其是在大型项目中。
  • 可读性:GN的构建文件(.gnBUILD.gn)比传统的Makefile更容易阅读和维护。
  • 跨平台:GN支持跨平台构建,可以在不同的操作系统上使用。

总的来说,GN的引入也是为了提高Android系统和Chromium等大型项目的构建效率。

gn的安装,可以从官网下载代码编译:

$git clone https://gn.googlesource.com/gn
$cd gn
$python build/gen.py
$ninja -C out

然后把二进制文件放到你的路径里即可。

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

假设你有一个简单的 C++ 项目,你需要编写一个 BUILD.gn 文件来告诉 GN 如何构建它。这个文件可能会包含如下内容:

# 定义一个可执行文件目标
executable("my_app") {sources = ["main.cc","utils.cc",]deps = ["//third_party/some_library",]
}

这个 BUILD.gn 文件定义了一个名为 my_app 的可执行文件,它依赖于 main.ccutils.cc 这两个源文件,以及一个名为 some_library 的第三方库。

在 Android 构建环境中,GN 的执行通常是自动的。这里为了方便理解,手动运行 GN,在项目根目录下运行以下命令:

$gn gen out/debug --dotfile=out/debug/gn_graph.dot

这个命令会生成一个名为 out/debug 的输出目录,生成一个 Ninja 构建文件。并创建一个名为 gn_graph.dot 的文件,该文件包含了构建图的 Graphviz 表示,用于可视化构建过程。

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

$ninja -f build.ninja

2.5 详细解读kati soong gn与Ninja之间的关系

Kati、Soong、GN 和 Ninja 都是构建系统组件。在 Android 系统的编译过程中,这些工具通常按照以下流程工作:

  • GN 将BUILD.gn转换为 Ninja 文件。
  • KatiAndroid.mk 转换为 Ninja 文件。
  • Soong 解析 Android.bp 文件并生成 Ninja 文件。
  • Ninja 读取生成的 Ninja 文件,并执行构建任务。

总的来说,GN Kati Soong相当于cmake的角色,而Ninja相当于make的角色。同时GN 和 Ninja 是现代构建系统的工具,而 Kati 和 Soong 是 Android 在从旧的 Make 构建系统过渡到基于 Ninja 的构建系统过程中引入的组件。

作为一个高效、轻量级的构建工具,在Android Framework的构建过程中发挥着重要作用。了解Ninja的原理和优势,可以帮助开发者更好地优化构建过程,提高开发效率。接下来用一个最简单的例子,我们来熟悉一下Ninja的编译流程。

3 构建一个最简单Ninja编译系统

构建一个最简单的 Ninja 编译系统,你需要以下2个文件:一个 C/C++ 源文件、一个 Ninja 构建文件。以下是一个简单的 "Hello, World!" 程序的例子。

3.1 源代码文件(hello.c

// hello.c
#include <stdio.h>int main() {printf("Hello, World!\n");return 0;
}

3.2 Ninja 构建文件(build.ninja

# 定义编译器
cflags = -Wall# 定义构建规则
rule cccommand = gcc $cflags -c $in -o $outdescription = Compiling $out# 定义构建目标
build hello.o: cc hello.c
build hello: link hello.ocommand = gcc -o $out $indescription = Linking $out

3.3 运行 Ninja 构建

首先,确保你已经安装了 Ninja。然后,在包含上述两个文件的目录中打开命令行,运行以下命令:

#默认路径
$ninja

这个命令会检查 build.ninja 文件中的指令,编译 hello.c 文件,并将其链接成可执行文件 hello。构建完成后,你可以运行生成的可执行文件:

$./hello
Hello, World!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/438757.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot集成encache快速入门Demo

1.什么是encache EhCache 是一个纯 Java 的进程内缓存框架&#xff0c;具有快速、精干等特点&#xff0c;是 Hibernate 中默认的 CacheProvider。 Ehcache 特性 优点 快速、简单支持多种缓存策略&#xff1a;LRU、LFU、FIFO 淘汰算法缓存数据有两级&#xff1a;内存和磁盘&a…

Linux bash脚本 远程开发环境配置

参考资料 太香了&#xff0c;VSCode远程开发插件&#xff0c;值得一试Visual Studio Code で Remote SSH する。Managing extensions 目录 一. 远程开发必备二. 连接远程开发服务器三. 安装远程开发插件 一. 远程开发必备 ⏹ VSCode插件 Remote - SSH 通过使用 SSH 链接虚拟…

C++之多态篇(超详细版)

1.多态概念 多态就是多种形态&#xff0c;表示去完成某个行为时&#xff0c;当不同的人去完成时会有不同的形态&#xff0c;举个例子在车站买票&#xff0c;可以分为学生票&#xff0c;普通票&#xff0c;军人票&#xff0c;每种票的价格是不一样的&#xff0c;当你是不同的身…

如何高效删除 MySQL 日志表中的历史数据?实战指南

在处理高并发的物联网平台或者其他日志密集型应用时&#xff0c;数据库中的日志表往往会迅速增长&#xff0c;数据量庞大到数百GB甚至更高&#xff0c;严重影响数据库性能。如何有效管理这些庞大的日志数据&#xff0c;特别是在不影响在线业务的情况下&#xff0c;成为了一项技…

使用Windows远程桌面连接Linux

要在Kali Linux上使用Windows远程桌面连接&#xff08;MSTSC.exe&#xff09;&#xff0c;你可以通过配置xrdp服务来实现。以下是在Kali Linux上设置xrdp以便Windows远程桌面连接的具体步骤&#xff1a; 一、安装xrdp和Xfce桌面环境 更新软件包列表&#xff1a; 打开终端&…

Python和C++混淆矩阵地理学医学物理学视觉语言模型和算法模型评估工具

&#x1f3af;要点 优化损失函数评估指标海岸线检测算法评估遥感视觉表征和文本增强乳腺癌预测模型算法液体中闪烁光和切伦科夫光分离多标签分类任务性能评估有向无环图、多路径标记和非强制叶节点预测二元分类评估特征归因可信性评估马修斯相关系数对比其他准确度 Python桑…

基于C++和Python的进程线程CPU使用率监控工具

文章目录 0. 概述1. 数据可视化示例2. 设计思路2.1 系统架构2.2 设计优势 3. 流程图3.1 C录制程序3.2 Python解析脚本 4. 数据结构说明4.1 CpuUsageData 结构体 5. C录制代码解析5.1 主要模块5.2 关键函数5.2.1 CpuUsageMonitor::Run()5.2.2 CpuUsageMonitor::ComputeCpuUsage(…

大数据技术:Hadoop、Spark与Flink的框架演进

大数据技术&#xff0c;特别是Hadoop、Spark与Flink的框架演进&#xff0c;是过去二十年中信息技术领域最引人注目的发展之一。这些技术不仅改变了数据处理的方式&#xff0c;而且还推动了对数据驱动决策和智能化的需求。在大数据处理领域&#xff0c;选择合适的大数据平台是确…

有些硬盘录像机接入视频汇聚平台EasyCVR后通道不显示/显示不全,该如何处理?

EasyCVR视频监控汇聚管理平台是一款针对大中型项目设计的跨区域网络化视频监控集中管理平台。该平台不仅具备视频资源管理、设备管理、用户管理、运维管理和安全管理等功能&#xff0c;还支持多种主流标准协议&#xff0c;如GB28181、RTSP/Onvif、RTMP、部标JT808、GA/T 1400协…

排序算法剖析

文章目录 排序算法浅谈参考资料评价指标可视化工具概览 插入排序折半插入排序希尔排序冒泡排序快速排序简单选择排序堆排序归并排序基数排序 排序算法浅谈 参考资料 数据结构与算法 评价指标 稳定性&#xff1a;两个相同的关键字排序过后相对位置不发生变化时间复杂度空间复…

数据挖掘-padans初步使用

目录标题 Jupyter Notebook安装启动 Pandas快速入门查看数据验证数据建立索引数据选取⚠️注意&#xff1a;排序分组聚合数据转换增加列绘图line 或 **&#xff08;默认&#xff09;&#xff1a;绘制折线图。bar&#xff1a;绘制条形图。barh&#xff1a;绘制水平条形图。hist&…

QT将QBytearray的data()指针赋值给结构体指针变量后数据不正确的问题

1、问题代码 #include <QCoreApplication>#pragma pack(push, 1) typedef struct {int a; // 4字节float b; // 4字节char c; // 1字节int *d; // 8字节 }testStruct; #pragma pack(pop)#include <QByteArray> #include <QDebug>int main() {testStruct …

leetcode练习 路径总和II

给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum 22 输出&a…

告别传统互动:AI数字人正全面进入人类社会

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 今天我们来聊聊AI数字人&#xff01; 当我…

全网最详细kubernetes中的资源

1、资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 kubernetes的本质上就是一个集群系统&#xff0c;用户可以在集群中部署各种服务。 所谓的部署服务&#xff0c;其实就是在kubernetes集群中运行一个个的…

C语言基础(7)之操作符(1)(详解)

目录 1. 各种操作符介绍 1.1 操作符汇总表 2. 移位操作符 2.1 移位操作符知识拓展 —— 原码、反码、补码 2.2 移位操作符讲解 2.2.1 右移操作符 ( >> ) 2.2.2 左移操作符 ( << ) 3. 位操作符 3.1 & (按位与) 3.2 | (按位或) 3.3 ^ (按位异或) 3.4…

gm/ID设计方法学习笔记(一)

前言&#xff1a;为什么需要gm/id &#xff08;一&#xff09;主流设计方法往往侧重于强反型区&#xff08;过驱>0.2V&#xff09;&#xff0c;低功耗设计则侧重于弱反型区&#xff08;<0&#xff09;&#xff0c;但现在缺乏对中反型区的简单和准确的手算模型。 1.对于…

10月2日笔记(内网资源探测篇)

内网资源探测 在内网渗透中&#xff0c;测试人员往往需要通过各种内网扫描技术来探测内网资源的情况&#xff0c;为后续的横向渗透做准备&#xff0c;通常需要发现内网存活的主机&#xff0c;并探测主机的操作系统、主机开放了哪些端口、端口上运行了哪些服务、服务的当前版本…

SQL SERVER 从嫌弃存储到爱上存储过程我给存储过程开发了版本控制工具和远程调试功能...

优缺点 SQL SERVER 爱上存储过程我给存储过程开发了版本控制工具和远程调试功能 先说说 存储过程的优缺点吧存储过程的优点 提高执行效率&#xff1a;存储过程是预编译的&#xff0c;执行速度较快&#xff0c;减少了网络传输量。 减少开发工作量&#xff1a;存储过程可以将复杂…

数据结构——对顺序线性表的操作

大家好啊&#xff0c;今天给大家分享一下对于顺序线性表的相关操作&#xff0c;跟随我的步伐来开始这一篇的学习吧&#xff01; 如果有知识性错误&#xff0c;欢迎各位指正&#xff01;&#xff01;一起加油&#xff01;&#xff01; 创作不易&#xff0c;希望大家多多支持哦…