扒一扒鸿蒙中的Gn与Ninja
liebian365 2025-01-02 17:42 40 浏览 0 评论
鸿蒙系统的编译构建是基于 Gn 和 Ninja 完成的,那么 Gn 和 Ninjia 有什么关系呢?具体又是如何工作的呢?
想必大多数热衷于应用开发的同学都还没有深究过,那么今天就借此机会带着大家扒一扒 Gn 和 Ninja。
我们先来说说 Ninja 吧!
Ninja 是借由 Google Chrome 项目而诞生的一个构建工具,它的诞生目标是为了速度。
换句话说,在 Google Chrome 项目的开发过程中,开发者们认为同类型的其它构建工具不给力,所以才会考虑重新开发更高效的工具。
要说同类型,那么不得不提构建界的老大哥 make !make 即 GNU Make,一个用于决定如何使用命令完成最终目标构建的程序。
在这里强调 make 的 3 个特性:
- make 只是一个通用程序,它不知道如何具体的完成目标的构建工作。
- make 需要 makefile 中的描述来决定目标构建的具体方案。
- make 需要借助其它工具(如:gcc)才能执行方案,最终完成工作。
这是不是跑题了!不是说好的讨论 Ninja 吗?怎么扯到 make 上去了?!
因为 Ninja 可以看作是一个更好的 make !而大多数同学都熟悉 make ,所以通过对比 make 学习 Ninja 是一个非常好的选择!
上述关于 make 的 3 个特性对于 Ninjia 同样适用(理论上,make 有的 Ninjia 都有,并且更好)。
那么,是不是得先学习 make 再学习 Ninja 呢?我觉得倒也不是!毕竟我们最终还是在鸿蒙上做应用开发,编译构建系统只需要大体了解即可。
接下来通过一个简单的例子向大家展示 Ninja 的用法!
test.c 是一个简单的 Hello World 程序,用于打印一个字符串和头文件 test.h 中常量 CONST 的值。
根据 C 程序的编译方式可知:
- 在预处理阶段 test.h 中的代码直接嵌入test.c 中(头文件 .h 最终成为源文件 .c 的一部分)。
- test.c 编译后得到目标文件 test.o。
- test.o 链接后得到最终的可执行程序 test.out。
各个文件在编译过程中有明显的上下游关系,即:上游文件影响或者产生下游文件。
上图即描述了编译过程,同时也反映了这样一个事实:任何一个文件被改动时只可能影响下游文件,而不会影响上游文件。
如:test.c 被修改了,那么可能导致编译得到 test.o 发生改变,进而导致最终的可执行程序 test.out 改变。因此,当 test.c 被修改时,那么应该重新触发编译和链接这两个动作。
看到这里,有同学可能存在这样的疑问:怎么知道文件已经被修改了并触发相应动作呢?
其实很简单,可以根据文件修改时间判断呀!目前几乎主流的文件系统都会记录文件被修改的时间,所以结合文件的上下游关系可知:上游文件被修改的时间应该总是 小于等于 下游文件被修改的时间。
这样,只需要遍历一次上面的构建图就可以知道执行哪些动作产生最终可执行程序了。
接下来思考这样一个问题:如何向构建工具 Ninja 描述构建图?
Ninja 的本质是一种通用程序。既然是程序,那么擅长的必然是处理结构化文本!因此,可以用结构化文本(Ninja 脚本)来描述构建图。
下面直接上代码:
解读:
①Ninja 脚本中的 build 语句描述构建图中的一个文件上下游关系。
如:build test.o cc test.c 指明 test.o 由 test.c 通过规则 cc 而构建,test.c 在构建图中位于 test.o 的上游,从 test.c 到 test.o 需要执行的动作通过规则 cc 定义。
Ninja 通过判断上下游文件的修改时间决定是否执行规则中定义的动作。多个 build 语句共同描述一个编译构建图。
②Ninja 脚本中通过 rule 定义规则描述构建图中需要执行的动作。
如:规则 cc 所定义的具体动作是 gcc -c $in -o $out ,其中 $in 指代上游文件, $out 指代下游文件。
对于 build test.o cc test.c 而言,最终执行的动作为:gcc -c test.c -o test.o 。
③由 C 语言及其编译方式可知:当源文件包含的头文件改动时,源文件需要重新编译。
因此,在构建图中头文件顺理成章的成为了源文件的上游文件,需要考虑的仅仅是如何定义 rule 最终触发编译动作。
这里使用的技巧是通过命令 touh 更新源文件的修改时间,于是可定义 rule dp 的执行动作为 touch $out。
这样 build test.c : dp test.h 的意思就很清楚了:当 test.h 被修改时,执行 touch test.c 更新修改时间,进而触发重新编译。
④default test.out 指明默认构建的目标是 test.out,即:ninja 执行当前脚本时默认编译构建的是 test.out。
理解了 Ninja 脚本的基本构成后就可以通过实验进一步体会了!
1. 将上面的脚本另存为文件,并重命名为 build.ninja,且与 test.c 和 test.h 位于同一目录下。
2. 打开命令行定位到源码目录,执行 ninja > log.txt。
通过编译输出(log.txt)以及 test.out 的运行结果可知目标构建成功。
后记:这只是一个 Ninja 的入门级介绍,更多的细节大家可以参考附件中的手册。
同时,文中的示例代码也可以在附件中下载。大家可以自己动手修改源码(比如:修改 test.h 中 CONST 的值)然后自行编译体会 Ninja 的用法。
作者: 唐佐林
原文链接:https://mp.weixin.qq.com/s/dyXDGBEH18sL5cW7bA-orQ
相关推荐
- python如何对字符串进行操作(python如何对字符串进行操作输出)
-
1.字符串的创建可通过直接赋值、构造或转义字符来创建字符串。#普通字符串s="Hello,World!"#多行字符串(使用三引号)multi_line_str='''Thisi...
- Excel表格中11个常用的字符串函数
-
今天和大家聊聊常用的字符串函数,在不同的条件下,如何选择字符串函数很关键。下面我为大家列举了11个关于字符串的函数公式。一、EXACT(两个字符串进行结果比较)比较两个字符串是否完全相同(这里是要区分...
- 详细介绍一下Python中如何对字符串进行操作?
-
在Python中,字符串做为一种常见的数据处理类型,几乎在每个应用程序中都会被用到。而作为Python中使用最广泛的数据类型Python也是提供了很多强大的方法来支持对于字符串的处理操作。下面我们就来...
- Java中你知道几种从字符串中找指定的字符的数量
-
遇到这样的问题,常规的思路估计就是遍历String,然后逐个对比。下面先看循环遍历循环遍历privatestaticintgetNum(StringoriginStr,Stringtarg...
- C语言strcspn函数详解:字符串的“扫雷探测器”
-
strcspn是C语言标准库中的一个函数,定义在头文件中。它用于计算从字符串的开始到首次出现任何属于指定字符集合的字符之间的字符数量。换句话说,strcspn计算的是主字符串中不包含指定字符集...
- 如何使用 Python 的 f-string 进行字符串格式化
-
Python中的字符串格式化曾经有点麻烦。必须在...
- java判断字符串中是否包含某个字符
-
1使用String类的contains()方法contains()方法用于判断字符串中是否包含指定的字符或字符串。语法如下:publicbooleancontains(CharSequence...
- Python基础:f-string不同数据类型的格式化选项,终极指南!
-
上一篇文章我们介绍了4种字符串格式化方法,其中最现代、最直观的方式是f-string,从Python3.6开始引入,而且时不时就增加一些超级优雅的小改进。今天,钢铁老豆想要继续给大家展开介绍不同数据...
- Excel查找指定字符串,返回相应的结果
-
通过下面的函数,可以实现查找指定字符串,若找到返回“有”,若找不到返回“无”。=IF(ISNUMBER(SEARCH("失业",G3)),"有","无")...
- 一个list中,有b.a.b.c.b.b.写个方法去掉所有b
-
importjava.util.ArrayList;importjava.util.List;publicclassRemoveBFromStringList{/**...
- 掌握Python f-string(掌握催眠能力之后的日常生活)
-
f-string,通常称为格式化字符串文本,是Python3.6中添加的一项强大功能,它提供了一种将表达式包含在字符串文本中的清晰实用的方法。,...
- 深入了解字符串:定义、转义字符和字符串下标
-
字符串是编程中常见的数据类型之一,用于表示文本信息。在绝大多数编程语言中,字符串都是由一系列字符组成的序列,可以包含字母、数字、符号以及空格等。字符串的定义:...
- 100个Java工具类之70:字符串处理工具类StringUtils
-
StringUtils是常用的工具类,提供大量处理字符串的静态方法。StringUtils主要特点...
- Shell中针对字符串的切片,截取,替换,删除,大小写操作
-
切片返回字符串变量var的长度...
- Sqlite - 常规函数 - RTRIM(sqlite命令行工具)
-
在SQLite中,RTRIM函数是一个用于处理字符串的函数,其主要作用是移除字符串右侧(尾部)的指定字符。如果不指定要移除的字符,默认会移除字符串右侧的空格字符。以下是对RTRIM函数的详细...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)