当前位置:首页 » 编程软件 » ninja编译能成功却少了东西

ninja编译能成功却少了东西

发布时间: 2025-03-23 12:46:19

Ⅰ 一文读懂ninja构建系统

许多大型项目,比如PyTorch,都把ninja作为构建系统的一部分。为了更好地理解这些项目,对ninja有一个初步的认识是非常必要的。

ninja是一种构建工具,用于调用各种工具(如代码生成器、编译器、链接器等)来编译大型项目。与cmake/make等工具不同,ninja并不是为人直接编写的,而是作为其他程序生成的目标。

ninja的设计哲学是避免任何模糊的内容。例如,makefile中可能会用dir/*.cpp来表示源文件,但需要查询文件系统才能得到具体内容,这是一个既慢又不确定的操作。ninja将这些模糊的操作都交给了元构建系统(如cmake),只留下真正需要编译的命令。

因此,本质上ninja就是一条一条地列出了具体要执行的命令,然后执行即可。

ninja会分析这一系列命令之间的依赖关系,并根据这个依赖关系实现两个重要特点。

ninja的安装方式有三种,具体可参见文档。总的来说,有三种安装方式:直接从GitHub下载、使用pip安装、使用conda安装。如果需要保证安全,可以通过ninja的GitHub release页面下载;如果图方便,可以使用各种社区维护的安装方式。

ninja的构建配置文件一般叫做build.ninja。虽然我们一般不直接编写它,但需要大致看懂它,以便调试或理解构建过程。

下面以一个简单的例子来说明常见的ninja配置:

有两个头文件a1.h和a2.h,分别定义了一个变量a,但是有不同的值。一份源文件a.cpp里根据宏的不同来包含这两个文件中的某一个。一份build.ninja文件包含了ninja的构建配置(注意最后的换行是必要的)。

有了这份build.ninja,我们可以通过ninja或者ninja compile_with_default_cxxflags来构建默认的代码,得到可执行文件compile_with_default_cxxflags;也可以通过ninja compile_with_shadow_cxxflags得到可执行文件compile_with_shadow_cxxflags。我们也可以修改a1.h或者a2.h,观察ninja是否会重新编译。

这份build.ninja里的大部分内容简单易懂,唯一难以理解的就是用于增量编译的depfile = $out.d。

首先,$out是ninja的默认变量,表示构建的目标文件名。所以$out.d就是目标文件名加上.d。比如build compile_with_default_cxxflags里,depfile就是compile_with_default_cxxflags.d。

然后我们需要理解增量构建的目标:我们的build compile_with_default_cxxflags构建条目中,只传入了a.cpp这一个文件,但是实际上我们的代码里面包含了a1.h或者a2.h。如何能够让ninja知道增量构建的时候需要检查a1.h或者a2.h呢?这就需要编译器的支持了:g++的-MM -MF $out.d参数会将文件与头文件的依赖关系输出到$out.d中,下次ninja就会通过这个文件的内容来判断具体需要检查发生改变的文件。

例如,compile_with_default_cxxflags.d文件里,就有以下内容:

下次ninja再build compile_with_default_cxxflags的时候,就会检查这个文件,然后查看a.cpp与a1.h的修改时间,如果任何一个文件被修改了,就重新编译。另外,如果compile_with_default_cxxflags文件不在了,ninja也会重新编译。

很多ninja.build里存在phony规则。这是一个内置规则,意思是“假冒的”,就是一个不存在规则的规则。我们可以理解为:

其中冒号:是unix系统里的一个命令,不管参数是什么,永远正常退出。因此,phony规则不会做什么,但是会在输入和输出之间建立依赖关系。

不带参数的ninja命令会构建文件里的default构建目标。我们也可以用ninja compile_with_shadow_cxxflags来手动构建某个目标。

构建多个目标(比如PyTorch有上千个目标)的时候,ninja会展示一个进度条,进度条展现的内容就是rule下面的description字段的内容。

ninja的高级用法一般都在ninja -t下面,例如ninja -t clean可以清理全部生成文件、ninja -t browse可以打开一个网页浏览器查看文件之间的依赖图(默认查看的是名为all的依赖图):

通过这个浏览器界面,我们可以很方便地查看什么文件依赖于什么文件。打开http://localhost:8000/?libtorch.so就可以看到完整的libtorch.so对应的依赖,再也不用对着CMakeLists.txt瞎猜了。(还可以通过ninja -t graph直接导出依赖图的dot graph文件,但是大型项目的依赖图一般都非常复杂,看起来不方便。)

最后,ninja -t targets all得到的是全部的构建目标,可以用于grep搜索想要的内容;ninja -C /path/to/dir -f /path/to/file可以让ninja切换到/path/to/dir去执行命令、并读取/path/to/file配置文件来执行。-f的默认参数是build.ninja,-C的默认参数为.,也就是当前路径。一般来说-f参数用得很少,-C参数用得比较多。

本文简单介绍了ninja的一些原理及用法。虽然简单,但依然起了个“一文读懂ninja构建系统”的标题,就是因为ninja真的很小,它的全部文档差不多也就这些值得我们关心的内容。

热点内容
android获取屏幕像素 发布:2025-03-24 22:21:18 浏览:844
解压密码忘记了 发布:2025-03-24 22:15:18 浏览:639
foxmail邮件的文件夹 发布:2025-03-24 22:14:37 浏览:565
脚本写I 发布:2025-03-24 22:13:28 浏览:850
ios10文件夹名称空白 发布:2025-03-24 22:11:56 浏览:137
linux编译php扩展 发布:2025-03-24 22:09:24 浏览:842
python二进制长度 发布:2025-03-24 22:07:50 浏览:602
电脑有wifi找不到服务器 发布:2025-03-24 22:06:22 浏览:550
企业解压拓展 发布:2025-03-24 22:04:44 浏览:531
中青看点脚本 发布:2025-03-24 21:51:07 浏览:473