Android中的Ninja简介
2017-11-23 10:58
375 查看
Android中的Ninja简介
如果说Makefile是一个DSL,那么Ninja就是一种配置文件。 本文简单介绍Android中的Ninja。
Makefile与Ninja的对比
二者最核心的区别,在于设计哲学。 Makefile是设计来给人手写的,而Ninja设计出来是给其它程序生成的。 如果说Makefile是C语言,那么Ninja就是汇编语言。如果说Makefile是一个DSL,那么Ninja就是一种配置文件。 Makefile支持分支、循环等流程控制,而Ninja只支持一些固定形式的配置。
二者的相同点是,都是为了控制编译流程而设计。 所以,他们的核心功能,都是指定目标,以及目标之间的依赖关系,自动计算执行顺序。
与Makefile相比,由于Ninja仅仅专注于核心的功能,所以有轻巧、速度快的优点。
Makefile默认文件名为
Makefile或
makefile,也常用
.make或
.mk作为文件后缀。 Ninja的默认文件名是
build.ninja,其它文件也以
.ninja为后缀。
执行Makefile的程序,默认是GNU make,也有一些其它的实现。 Ninja的执行程序,就是
ninja命令。
在Android项目中,
make需要编译主机上安装,作为环境的一部分。 而
ninja命令则是Android平台代码自带。
$ find prebuilts/ -name ninja prebuilts/build-tools/linux-x86/asan/bin/ninja prebuilts/build-tools/linux-x86/bin/ninja prebuilts/build-tools/darwin-x86/bin/ninja
ninja命令的用法
通过ninja -h,可以看到该命令的帮助文档。
$ ninja -h usage: ninja [options] [targets...] if targets are unspecified, builds the 'default' target (see manual). options: --version print ninja version ("1.7.2") -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 [default=6, derived from CPUs available] -k N keep going until N jobs fail [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) -v show all command lines while building -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 -w FLAG adjust warnings (use -w list to list warnings)
很多参数,和
make是比较类似的,比如
-f、
-j等,不再赘述。
有趣的是
-t、
-d、
-w这三个参数,最有用的是
-t。
$ 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 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 -t clean是清理产物,是自带的,而
make clean往往需要自己实现。 其它都是查看编译过程信息的工具,各有作用,可以进行复杂的编译依赖分析。
Ninja的专注,在这里完全超越了Makefile。
Android中的Ninja文件
从Android 7开始,编译时默认使用Ninja。 但是,Android项目里是没有.ninja文件的。
遵循Ninja的设计哲学,编译时,会先把Makefile通过kati转换成
.ninja文件,然后使用
ninja命令进行编译。
这些
.ninja文件,都产生在
out/目录下,共有三类。
一类是
build-*.ninja文件,通常非常大,几十到几百MB。 对
make全编译,命名是
build-<product_name>.ninja。
如果Makefile发生修改,需要重新产生Ninja文件。
这里Android有一个bug,或者说设计失误。
mm、
mma的Ninja文件,命名是
build-<product_name>-<path_to_Android.mk>.ninja。
而
mmm、
mmma的Ninja文件,命名是
build-<product_name>-_<path_to_Android.mk>.ninja。
显然,不同的单模块编译,产生的也是不同的Ninja文件。
这个设计本身就有一些问题了,为什么不同模块不能共用一个总的Ninja文件? 这大概还是为了兼容旧的Makefile设计。 在某些Android.mk中,单模块编译与全编译时,编译内容截然不同。 如果说这还只能算是设计失误的话,那么
mm与
mmm使用不同的编译文件,就是显然的bug了。
二者相差一个下划线
_,通过
mv或
cp,可以通用。
第二类是
combined-*.ninja文件。 在使用了Soong后,除了
build-*.ninja之外,还会产生对应的
combined-*.ninja,二者的
*内容相同。
以下以AOSP的aosp_arm64-eng为例,展示
out/combined-aosp_arm64.ninja文件的内容。
builddir = out include out/build-aosp_arm64.ninja include out/soong/build.ninja build out/combined-aosp_arm64.ninja: phony out/soong/build.ninja
这类是组合文件,是把
build-*.ninja和
out/soong/build.ninja组合起来。
所以,使用Soong后,
combined-*.ninja是编译执行的真正入口。
第三类是
out/soong/build.ninja文件,它是从所有的
Android.bp转换过来的。
build-*.ninja是从所有的Makefile,用Kati转换过来的,包括
build/core/*.mk和所有的
Android.mk。
所以,在不使用Soong时,它是唯一入口。 在使用了Soong以后,会新增源于
Android.bp的
out/soong/build.ninja,所以需要
combined-*.ninja来组合一下。
可以通过以下命令,单独产生全编译的Ninja文件。
make nothing
用ninja编译
在产生全编译的Ninja文件后,可以绕过Makefile,单独使用ninja进行编译。
全编译(7.0版本),相当于
make:
ninja -f out/build-aosp_arm64.ninja
单独编译模块,比如Settings,相当于
make Settings:
ninja -f out/build-aosp_arm64.ninja Settings
在8.0以上,上面的文件应该替换为
out/combined-aosp_arm64.ninja,否则可能找不到某些Target。
另外,还有办法不用输入
-f参数。 如前所述,如同Makefile之于
make,
ninja默认的编译文件是
build.ninja。
所以,使用软链接,可以避免每次输入繁琐的
-f。
ln -s out/combined-aosp_arm64.ninja build.ninja ninja Settings
用
ninja进行单模块编译的好处,除了更快以外,还不用生成单模块的Ninja文件,省了四五分钟。
总结
在以Ninja在实际编译中替换Makefile以后,Android在编译时更快了一些。 不过,在首次生成、或重新生成Ninja文件时,往往额外耗时数分钟,反而比原先使用Makefile更慢了。在增量编译方面,原先由于其Makefile编译系统的实现问题,是不完善的。 也就是说,在
make编译完一个项目后,如果再执行
make,会花费较长时间重新编译部分内容。
而使用Ninja以后,增量编译做得比较完善,第二次
make将在一分钟内结束。
除此之外,由于Ninja的把编译流程集中到了一个文件,并且提供了一些工具命令。 所以编译信息的提取、编译依赖的分析,变得更加方便了。
相关文章推荐
- Android中的Ninja简介
- Android中Toast的用法简介
- Android——简介
- Android开发学习之Activity的简介
- 【Android应用开发】Android Studio 简介 (Android Studio Overview)
- Android文件夹功能简介
- 【Android】【Webview】WebView 简介
- Android ActivityThread(主线程或UI线程)简介
- 六款值得推荐的android(安卓)开源框架简介
- 【转】值得推荐的android开发框架简介
- Android开发-自定义View-AndroidStudio(四)简介动画
- Android 系统启动流程简介
- Qualcomm_Snapdragon_VR_SDK SvrPluginAndroid脚本简介(5)
- Android画图学习总结(一)——类的简介
- android.mk简介及如何直接执行C代码
- Android内存泄漏简介
- android的Manifest.xml文件配置简介
- Android.mk简介 .
- Android之---RecycleView简单介绍(各种用法的简介)