Ninja使用教程【含官方文档翻译】

2024-04-13 01:36

本文主要是介绍Ninja使用教程【含官方文档翻译】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

ninja官方文档是英文版,查阅起来不方便,所以自制一版中文版本,方便快速查找

附带自己练习使用的demo代码,适合初学者入门练习,有不懂的关键字直接在此页面搜索

使用搜索快捷键:ctrl+f

译自Ninja版本 v1.11.1, Aug 2022

官方文档链接:The Ninja build system (ninja-build.org)

生词解释:

构建边(build edge):通常指每个build的执行语法。

NInja 介绍

Ninja是另外一个构建系统,它可以根据文件的依赖关系(文件通常指源代码和输出的可执行文件)快速的编排和构建代码。

笔者注:Ninja的特点就是可以把源代码文件和输出目标紧密联系起来,输入和输出很明确。后面会讲到。

Ninja 中加入了特别多其他构建系统。 而它本身的特点就是速度快。 它的首次使用是在开源的 Chromium 浏览器项目里,该项目拥有超过 30,000 个源文件,其他构建系统(包括自定义的非递归 Makefile)在更改一个文件后需要 10 秒才能开始构建。 Ninja只需要不到一秒。

Ninja 理念

其他构建系统都是高级语言,而 Ninja 的目标是成为汇编程序。

决策逻辑会使构建系统变慢,当你不断的编写代码、编译代码时,你会希望编译速度尽可能地快。换句话说,你希望构建系统在每次立即构建时做的工作最少。

Ninja包含描述任意依赖关系的必需的最基本功能,它没有表达复杂判断的语法。

与之对应,Ninja的用法是针对每一个输入文件单独进行生成输出。生成器程序(如 autotools 项目中的 ./configure)可以分析系统依赖项并预先做出尽可能多的决策,以便保持快速的增量构建。

除了自动工具,甚至构建时的决策例如“我应该使用哪个编译器标志?” 或“我应该构建调试(debug)或发布模式(release)的二进制文件吗?”这种问题都可以交给 .ninja 类型的文件生成器

Ninja的设计目标

以下是 Ninja 的设计目标:

  • 非常快速(即时)的增量构建,即使对于非常大的项目也是如此。
  • 代码的构建方案很少。不同的项目和高级构建系统关于如何构建代码有不同的配置方法。例如,构建的输出对象应该与源代码放在一起,还是所有构建输出都应该放入单独的目录中?是否有一个“包”规则来给项目构建一个可分发的包?通过允许尝试执行任何指令而不是选择参数的方法,来回避使用中的决策判断,即使这会导致语法更加冗长。
  • 获取正确的依赖关系,尤其是当Makefiles无法获取正确依赖的情况下。例如,某些输出需要隐式依赖生成命令行,当你构建C语言源文件时你需要使用gcc的 -M 标志去标识头文件的依赖。
  • 当方便和速度发生冲突时,优先选择速度。

一些明确不支持的目标:

  • 可以手写构建文件的便捷语法。您应该使用另一个程序生成 .ninja 文件。这也是我们为什么可以回避很多的方法决策。
  • 内置规则。 Ninja 没有开箱即用的规则,例如: 编译C代码。
  • 在构建时自定义。配置参数应放在项目中生成的ninja文件。
  • 在构建时做决策例如条件判断和查找路径。做决策是非常慢的。

重申一下,Ninja 比其他构建系统更快,因为它非常简单。 当您创建项目的 .ninja 文件时,您必须准确地告诉 Ninja 要做什么。

笔者注:ninja文件一般由CMAKE等工具生成,但也有很多项目直接使用ninja,直接使用ninja更灵活但是对开发者要求也更高

对比MAKE

Ninja 在精神和功能上与 Make 最接近,依靠简单的依赖关系中的文件时间戳运行。

笔者注:当一句语法中文件的时间戳变化了,ninja会将这个指令执行,以实现增量构建(不用每次都全部构建一遍)

但本质上来说,make 有很多功能:后缀规则、函数、内置规则,例如:构建源代码时搜索 RCS 文件。Make 的语言被设计为由人类编写。许多项目发现 make 足以解决他们的构建问题。

相比之下,Ninja几乎没有什么特色; 只要那些正确构建所必需的内容,同时将大部分复杂性都放在生成Ninja输入文件上。

Ninja 本身不太可能对大多数项目有用。

以下是Ninja对比Make增加的一些功能(这些功能通常可以使用更复杂的 Makefile 来实现,但它们不是 make 本身的一部分。)

Ninja 更加支持在构建时发现额外的依赖项,从而可以简单得到正确的 C/C++ 代码标头依赖项。

一个构建边缘可能有多个输出。

输出隐式依赖于用于生成它们的命令行,也可以意味着输入被修改。例如修改构建命令将导致重新构建。

输出目录通常在构建命令前隐士创建。

规则可以提供正在运行的命令的简短描述,因此您可以打印输出。例如在构建时取代长命令行。

构建始终并行运行,默认情况下基于系统拥有的 CPU 数量。未指定的构建依赖项将导致错误的构建。

命令输出始终被缓冲。 这意味着并行运行的命令不会交错其输出,并且当命令失败时,我们可以在产生失败的完整命令行旁边打印其失败输出。

为你的项目使用Ninja

Ninja 目前可以在类 Unix 系统和 Windows 上运行。 它在 Linux 上进行了最多的测试(并且具有最好的性能),但它在 Mac OS X 和 FreeBSD 上也能运行良好。

如果您的项目很小,Ninja 对速度的影响可能不明显。 (但是,即使对于小型项目,有时 Ninja 有限的语法也会强制采用更简单的构建规则,从而加快构建速度。)换句话说,如果您对项目的编辑-编译周期时间感到满意,那么Ninja就没有更多帮助。

还有许多其他构建系统比 Ninja 本身更加用户友好或功能更强大。 一些建议:Ninja作者发现tup构建系统对Ninja的设计有影响,并认为redo的设计相当聪明。

Ninja 的好处来自于将其与更智能的元构建系统结合使用。

gn

元构建系统用于为 Google Chrome 和相关项目(v8、node.js)以及 Google Fuchsia 生成构建文件。 gn 可以为 Chrome 支持的所有平台生成 Ninja 文件。

CMake

一种广泛使用的元构建系统,从 CMake 版本 2.8.8 开始,可以在 Linux 上生成 Ninja 文件。 较新版本的 CMake 也支持在 Windows 和 Mac OS X 上生成 Ninja 文件。

others

Ninja 应该完美地融入其他元构建软件,如 premake。 如果您从事这项工作,请告诉我们!(Ninja团队,不是笔者;)

运行Ninja

默认情况下,它会查找当前目录中指定的文件并构建所有过时的目标。 您可以指定要构建的目标(文件)作为命令行参数。

ninja build.ninja

还有一种特殊的语法,用于将目标指定为某些规则的第一个输出,该规则包含您在命令行中放入的源(如果存在)。例如,如果您指定目标文件,那么它将被构建(假设您的构建文件中有这些目标)。

target^foo.c^foo.o

ninja -h 打印帮助输出。 Ninja 的许多标志故意与 Make 的标志相匹配。例如:更改到目录并并行运行 20 个构建命令。(请注意,Ninja 默认情况下会并行运行命令,因此通常不需要传递 .)

ninja -C build -j 20build-j

环境变量

Ninja 支持使用环境变量来控制其行为,在运行规则之前打印进程状态。

.NINJA_STATUS

可用的占位符:

%s
开始构建边的数量。
%t
完成构建必须运行的边总数。
%p
开始边缘的百分比。
%r
当前运行的边的数量。
%u
要启动的剩余边数。
%F
完成的边数。
%o
每秒完成边缘的总体速率
%C
当前每秒完成边缘的速率(由指定或其默认值指定的构建的平均值)-j
%e
已用时间(以秒为单位)。 (自 Ninja 1.2 起可用。)
%%
一个普通的百分号%

默认进度状态是(注意尾随空格以与构建规则分开)。"[%f/%t] "

另一个示例:"[%u/%r/%f] "

Ninja工具(命令行指令)

可以使用Ninja的命令行运行一些我们开发过程中发现的其他工具,例如:

query

转储给定目标的输入和输出。(生成dump)

browse

在 Web 浏览器中浏览依赖关系图。 单击文件会将视图集中在该文件上,显示输入和输出。 此功能需要安装 Python。 默认情况下使用端口 8000,并且将打开 Web 浏览器。 可以按如下方式更改:

ninja -t browse --port=8000 --no-browser mytarget

graph

使用自动图形布局工具所使用的语法输出文件。例如Graphviz

ninja -t graph mytarget | dot -Tpng -ograph.png

在 Ninja 源代码树中,为 Ninja 本身生成图像。 如果没有给出目标,则为所有根目标生成一个图表。ninja graph.png

targets

按规则或按深度输出目标列表。如果像这样使用,它会使用要构建的给定规则打印目标列表。 如果没有给出规则,它将打印源文件(图形的叶子)。 如果像这样使用,它会从根目标(没有输出的目标)开始以深度优先的方式打印目标列表。 缩进用于标记依赖关系。 如果深度为零,则打印所有目标。 如果没有提供参数则假定。 在此模式下,目标可能会被列出多次。 如果像这样使用,它将打印所有可用的目标而无需缩进,并且比深度模式更快。

ninja -t targets rule name
ninja -t targets depth digit
ninja -t targets depth 1
ninja -t targets all

commands

给定一个目标列表,打印一个命令列表,如果按顺序执行,这些命令可以用于重建这些目标,假设所有输出文件都已过期。

inputs

给定目标列表,打印用于重建这些目标的所有输入的列表。 自 Ninja 1.11 起可用。

clean

删除构建的文件。 默认情况下,它会删除除生成器创建的文件之外的所有构建文件。 添加该标志还会删除生成器创建的构建文件(请参阅生成器属性的规则参考)。 -g

其他参数是目标,它删除给定的目标并递归地删除为其构建的所有文件。

如果像这样使用,它将删除使用给定规则构建的所有文件。

ninja -t clean -r rules

创建但未在图表中引用的文件不会被删除。This tool takes in account the and the options (note that implies ).-v-n-n-v (这句看不懂,有看懂的朋友请留言)

cleandead

删除以前构建生成的、不再包含在构建文件中的文件。 自 Ninja 1.10 起可用。

compdb

给定一个规则列表,其中每个规则都应该是 C 系列语言编译器规则,其第一个输入是源文件的名称,在标准输出上以 Clang 工具接口期望的 JSON 格式打印编译数据库。 自 Ninja 1.2 起可用。

deps

显示文件中存储的所有依赖项。 当给定目标时,仅显示目标的依赖关系。 自 Ninja 1.4. 起可用.ninja_deps

missingdeps

给定目标列表,查找依赖于生成的文件,但对生成器没有正确(可能是传递的)依赖关系的目标。 这些目标可能会导致干净构建的构建不稳定。

假设 deps log / depfile 依赖信息正确,就可以找到损坏的目标。 任何隐式依赖于生成文件(生成器目标的输出)但没有到生成器目标的显式或仅顺序依赖路径的目标都被视为损坏。

The tool’s findings can be verified by trying to build the listed targets in a clean outdir without building any other targets. The build should fail for each of them with a missing include error or equivalent pointing to the generated file. Available since Ninja 1.11.

recompact

重新压缩文件。 从 Ninja 1.4 开始可用。.ninja_deps

restat

更新文件中所有记录的文件修改时间戳。 自 Ninja 1.10.起可用 .ninja_log

rules

输出所有规则的列表。 它可用于了解要传递给哪个规则名称,添加标志还会打印规则的描述。

msvc

仅适用于 Windows 主机。 使用一组预定义的环境变量调用编译器的辅助工具,例如cl.exe

ninja -t msvc -e ENVFILE -- cl.exe <arguments>

这个二进制文件,其中包含适合 Windows 上的 CreateProcessA() 的环境块(即一系列看起来像 NAME=VALUE 的以零结尾的字符串,后跟一个额外的零终止符)。 请注意,这使用本地代码页编码。.ENVFILE

该工具还支持一种已弃用的方法,即在使用该标志时解析编译器的输出,并从中生成 GCC 兼容的 depfile。 /showIncludes

使用此选项时,可用于传递用于输出依赖关系信息的本地化行前缀。 对于英语区域,这不带双引号,但对于其他区域会有所不同。-p STRING cl.exe "Note: including file: "

请注意,Ninja 现在原生支持此功能,并在 Ninja 文件中使用。原生支持还避免了每次必须调用编译器时启动额外的工具进程,这可以显着加快 Windows 上的构建速度。

deps = msvcmsvc_deps_prefix

wincodepage

可在 Windows 主机上使用(自 Ninja 1.11 起)。 打印构建文件中预期其编码的 Windows 代码页。 输出的形式为:

Build file encoding: <codepage>

Ninja 的未来版本中可能会添加其他行。

The is one of:<codepage>

UTF-8

Encode as UTF-8.

ANSI

Encode to the system-wide ANSI code page.

编写你的Ninja文件

本手册的其余部分仅在您自己构建 Ninja 文件时有用:例如,如果您正在编写元构建系统或支持新语言。

概念概述

Ninja 通过分析文件之间的依赖关系图,并运行根据文件的修改时间确定的使构建目标保持最新所需的任何命令。 如果你熟悉 Make,Ninja 非常相似。

构建文件(默认名称:build.ninja)提供规则列表 — 较长命令的短名称,例如如何运行编译器 — 以及构建语句列表,说明如何使用规则构建文件 — 要应用哪个规则 哪些输入产生哪些输出。

从概念上讲,构建语句描述项目的依赖关系图,而规则语句描述如何沿着图的给定边缘生成文件。

语法示例

这是一个基本的 .ninja 文件,演示了大部分语法。 它将用作以下部分的示例。

cflags = -Wallrule cccommand = gcc $cflags -c $in -o $outbuild foo.o: cc foo.c

变量

尽管便于手写、保证构建文件可读性不是Ninja的目标,Ninja仍然支持为字符串声明较短的重命名,例如下面这样声明:

cflags = -g

可以用在等号的右侧,用美元符号取消引用它,如下所示:

rule cccommand = gcc $cflags -c $in -o $out

变量也可以使用花括号来引用,例如 ${in}。

变量最好称为“绑定”,因为给定的变量不能更改,只能隐藏。本文档后面将详细介绍隐藏的工作原理。

规则

规则是声明命令行的短名称。 它们由规则关键字(rule)和规则的名称开头。 然后是一组 较短的变量名 = 值  组成的行。

上面的基本示例声明了一个名为 cc 的新规则以及要运行的命令。 在规则的上下文中,command 变量定义要运行的命令,$in 扩展为输入文件列表 (foo.c),$out 扩展为命令的输出文件 (foo.o)。 参考资料中提供了特殊变量的完整列表。The Ninja build system (ninja-build.org)

构建语句

构建语句 声明输入和输出文件之间的关系。 它们以 build 关键字开头,并按照指定格式构建输出:从规则名称输入的格式。 这样的声明表示所有输出文件都源自输入文件。 当输出文件丢失或输入更改时,Ninja 将运行规则来重新生成输出。

上面的基本语法示例描述了如何使用 cc 规则构建 foo.o。

在构建块的范围内(包括对其关联规则的解析),变量 $in 是输入列表,变量 $out 是输出列表。

构建语句的后面可能跟着一组 关键值(key)= 值 的对,就跟规则中的一样。在解析command指令中的变时,这些变量将替换语句中原本的key,例如:

cflags = -Wall -Werror
rule cccommand = gcc $cflags -c $in -o $out# If left unspecified, builds get the outer $cflags.
build foo.o: cc foo.c# But you can shadow variables like cflags for a particular build.
build special.o: cc special.ccflags = -Wall# The variable was only shadowed for the scope of special.o;
# Subsequent build lines get the outer (original) cflags.
build bar.o: cc bar.c

笔者注:简单来说就是可以在你希望执行特殊的build语句时,可以使用在build语句后面重定义变量的方式修改已经定义好的构建规则(示例里的rule cc)

有关范围界定如何工作的更多讨论,请参阅参考资料。The Ninja build system (ninja-build.org)

如果您需要从构建语句传递到规则的更复杂的信息(例如,如果规则需要“第一个输入的文件扩展名”),请将其作为额外变量传递,就像上面传递 cflags 的方式一样。

如果顶层 Ninja 文件被指定为任意构建语句的输出,并且该文件已过时,Ninja 将在构建用户请求的目标之前将它重新构建并重新加载它。

用代码生成 Ninja 文件

Ninja 发行版中的misc/ninja_syntax.py 是一个很小的Python 模块,用于方便生成Ninja 文件。它允许你使用python调用例如

ninja.rule(name='foo', command='bar', depfile='$out.d')

并且它将生成对应的语法。如果有用的话,请随意将其内联到项目的构建系统中。

更多细节

规则:phony

特殊规则名称 phony 可用于为其他目标创建别名。(笔者译:phony 假名) 例如:

build foo: phony some/file/in/a/faraway/subdir/foo

这使得 ninja foo 指定了更长的构建路径。从语义上讲,phony规则相当于command不执行任何操作的普通rule,但phony规则经过特殊处理,因为它们在运行、记录时不会打印输出(见下文),也不会在构建过程中,对作为打印输出的一部分,对命令计数产生影响。

笔者注:就是不会打印输出也不会计入构建计数的统计,类似C语言中的宏定义在代码中的使用

当一个假名目标(长路径目标被phony之后的别名)在另一个构建规则内被作为输入使用时,另一个构建规则在语义上会将phony目标规则的输入视为自己的输入。

因此,可以使用phony规则对输入进行分组,例如 头文件。

phony 还可以用于为构建时可能不存在的文件创建虚拟目标。如果编写的phony构建语句没有任何的依赖项,如果其目标不存在就将被视为过时文件。如果没有使用phony构建语句,如果文件不存在且构建时需要它,ninja将会报错。

如果要创建一个永远不重新构建的规则,请不要带任何的输入:

rule touchcommand = touch $out
build file_that_always_exists.dummy: touch
build dummy_target_to_follow_a_pattern: phony file_that_always_exists.dummy

默认目标语句

默认情况下,如果在命令行上未指定目标,Ninja 将构建未在其他地方命名为输入的每个输出目标。您可以使用默认目标语句覆盖此行为。如果命令行上没有指定目标,则默认的目标语句会导致 Ninja 仅构建给定的输出文件的子集。

默认目标语句以 default 关键字开头,并符合默认目标语句的格式。默认目标语句必须出现在将这个默认目标声明为输出文件的构建语句之后。他们是累计的,因此可以使用多个语句来扩展默认目标列表。例如:

default foo bar
default baz

这样会让 Ninja 默认构建 foo、bar 和 baz 目标。

Ninja的log

对于每个构建的文件,Ninja 都会保存用于构建它的命令的日志。 使用此日志,Ninja 可以知道何时使用与构建文件指定的不同的命令行构建现有输出(即命令行已更改),并重新构建目标文件。

日志文件保存在构建根目录中名为 .ninja_log 的文件中。 如果您在最外层作用域中提供名为 builddir 的变量,则 .ninja_log 将保留在该目录中。

版本兼容性

自 Ninja 1.2 起可用。

Ninja 版本标签遵循标准的 Major.minor.patch 格式,其中主要版本在向后不兼容的语法/行为更改上增加,次要版本在新行为上增加。 您的 build.ninja 可以声明一个名为 ninja_required_version 的变量,该变量断言使用所需的最低 Ninja 版本。 例如:

ninja_required_version = 1.1

声明构建文件依赖于 Ninja 1.1 中引入的某些功能(比如pool语法),并且必须使用 Ninja 1.1 或更高版本进行构建。与其他 Ninja 变量不同,当解析中遇到该变量时,会立即检查此版本要求,因此最好将其放在构建文件的顶部。

如果你的 Ninja 的主版本和 ninja_required_version 不匹配,Ninja 会发出警告;主版本变更还没有发生,所以很难预测会发生什么。

C/C++ 头文件依赖

为了获取 C/C++ 标头依赖项(或以类似方式工作的任何其他构建依赖项),Ninja 有一些额外的功能。

标头的问题在于,给定源文件所依赖的文件的完整列表只能由编译器发现:不同的预处理器定义和包含路径会导致使用不同的文件。 一些编译器可以在构建时发出此信息,Ninja 也可以使用这种方法来完善其依赖项。

思考一下:如果文件从未被编译过,则无论如何都必须构建它,从而生成标头依赖项作为副输出项。如果以后修改任何文件(即使以更改其所依赖的标头的方式),修改也会导致重新构建,从而使依赖项保持最新。

加载这些特殊依赖项时,Ninja 会隐式添加额外的构建边缘,这样如果列出的依赖项缺失,也不会出现错误。 这允许您删除头文件并重新构建,而不会因缺少输入而中止构建。

depfile

gcc(以及 clang 等其他编译器)支持在 Makefile 语法中发送依赖关系信息。 (任何可以以这种形式编写依赖项的命令都可以使用,而不仅仅是 gcc。)

要将这些信息引入Ninja需要配合,在 Ninja 里,构建时的 depfile 属性必须指向写入此数据的路径。(Ninja 仅支持 Makefile 语法等有限子集的编译器发送依赖信息)然后该命令必须明确将依赖项写入 depfile 路径。例如:

rule ccdepfile = $out.dcommand = gcc -MD -MF $out.d [other gcc flags here]

gcc 的 -MD 标志告诉它要输出标头依赖项,而 -MF 标志告诉它在哪里写入它们。

deps

(自 Ninja 1.3 起可用。)

事实证明,对于大型项目(尤其是在文件系统速度较慢的 Windows 上),在启动时加载这些依赖文件的速度很慢。

Ninja 1.3 可以在生成依赖项后立即对其进行处理,并将相同信息的压缩形式保存在 Ninja 内部数据库中。

Ninja 以两种形式支持此处理。

  1. deps = gcc 指定该工具以 Makefile 的形式输出 gcc 风格的依赖项。 将其添加到上面的示例中将使 Ninja 在编译完成后立即处理 depfile,然后删除 .d 文件(仅用作临时文件)。
  2. deps = msvc 指定该工具以 Visual Studio 编译器的 /showIncludes 标志生成的格式输出标头依赖项。简而言之,这意味着该工具将特殊格式的行输出到stdout,然后,Ninja 从显示的输出中过滤这些行。不能有depfile 属性,但是头文件前面的路径必须是本地化的字符串。例如英文的Visual Studio(默认)
    msvc_deps_prefix = Note: including file:

    应该首先在全局定义。完整示例:

    msvc_deps_prefix = Note: including file:
    rule ccdeps = msvccommand = cl /showIncludes -c $in /Fo$out

如果包含目录指令使用绝对路径,则您的 depfile 可能会相对路径和绝对路径的混合使用。路径需要和其他的构建规则完全匹配。因此,建议在这些情况下使用相对路径。

池语法(Pools)

自 Ninja 1.1 起可用。

池允许您为一个或多个rule或build分配有限数量的并发。比默认的并发更好的操控。

这可能很有用,例如,去限制一个指定的重要规则(比如一个大型可执行文件的链接步骤),或者你已知在并发时会运行不佳的特定build语句。

每个池都有一个在构建文件中指定的深度变量。然后,在规则或构建语句上使用池变量引用该池。

无论您指定什么池,ninja 运行的并发数都不会超过默认并行数,以及在命令行上指定的并发数量(使用 -j)。

# No more than 4 links at a time.
pool link_pooldepth = 4# No more than 1 heavy object at a time.
pool heavy_object_pooldepth = 1rule link...pool = link_poolrule cc...# The link_pool is used here. Only 4 links will run concurrently.
build foo.exe: link input.obj# A build statement can be exempted from its rule's pool by setting an
# empty pool. This effectively puts the build statement back into the default
# pool, which has infinite depth.
build other.exe: link input.objpool =# A build statement can specify a pool directly.
# Only one of these builds will run at a time.
build heavy_object1.obj: cc heavy_obj1.ccpool = heavy_object_pool
build heavy_object2.obj: cc heavy_obj2.ccpool = heavy_object_pool

console pool

自 Ninja 1.5 起可用。

存在一个名为 console 的预定义池,深度为 1。它具有特殊的属性,即池中的任何任务都可以直接访问提供给 Ninja 的标准输入、输出和错误流,这些流通常连接到用户的控制台(因此得名),但也可以重定向。这对于在控制台上生成状态更新的交互式任务或长时间运行的任务(例如测试套件)非常有用。

当控制台池中的任务正在运行时,Ninja 的常规输出(例如进度状态和并发任务的输出)将被缓冲,直到其完成。

Ninja 文件参照

文件内是一系列声明。 声明可以是以下之一:

  • 规则声明,以rule rulename开头,然后有一系列定义变量的缩进行。
  • 构建边缘,看起来像
    build output1 output2: rulename input1 input2. 

    隐式依赖关系可以用 | 添加到末尾。

    build output1 output2: rulename input1 input2 | dependency1 dependency2

    单指令依赖项可以用 || 添加到末尾。

    build output1 output2: rulename input1 input2 || dependency1 dependency2

    校验项可以用 |@ 添加到末尾。

    build output1 output2: rulename input1 input2 |@ validation1 validation2

    依赖项和校验项参阅下文或原文The Ninja build system (ninja-build.org),隐式输出(自 Ninja 1.7 起可用)可以添加在 : 之前。

    build output1 output2 | output3 output4: rulename input1 input2

    输出3和4不会出现在 $out 中。参阅下文的输出类型或原文The Ninja build system (ninja-build.org)

  • 变量声明,比如

    variable = value.
  • 默认目标语句,例如
    default target1 target2.
  • 提交更多文件,例如
    subninja path
    include path

    两种方法的区别参考下文或Ninja构建系统 (ninja-build.org)

  • 池声明,例如
    pool poolname

    参考池语法部分介绍

词汇语法

Ninja 基本上与编码格式无关,只需要 Ninja 关心的字节(如路径中的斜杠)是 ASCII。 这意味着例如 UTF-8 或 ISO-8859-1 编码类型的输入文件都应该可以工作。

注释以 # 开头,注释当前行。

换行符很重要。 像 build foo bar 这样的语句是一组以空格分隔的标记,以换行符结尾。 token内的换行符和空格必须进行转义。

语法中只有一个转义字符$,它可以有以下行为:

$ 后面接新的指令行:

转义换行符(跳过换行符继续当前行)。

$ 后面接名字

表示变量。

${varname}

$varname 的替代语法。

$ 后面接空格

表示空格。 (这只在路径列表中有用,否则路径中的空格会分隔文件名。请参见下文。)

$:

表示冒号(:)(旨在build指令中有用,否则冒号会终止输出列表)

$$

字面意义的$。表示美元符。

build或default语句首先被解析为以空格分隔的文件名列表,然后扩展成每个名称。 这意味着变量中的空格将导致扩展文件名时出现空格。

spaced = foo bar
build $spaced/baz other$ file: ...
# The above build line has two outputs: "foo bar/baz" and "other file".

在name = value类型的语句里,name开头的空格始终会被删除。 用转义字符换行之后行首的空白也会被删除。

two_words_with_one_space = foo $bar
one_word_with_no_space = foo$bar

其他空格只有在一行的开头时才有意义(用来表示缩进)。如果一行缩进比前一行多,则它被视为其父行范围的一部分;如果缩进量小于前一个,则关闭前一个作用域。

顶层变量

在最外层文件作用域中声明时,有两个变量很重要。

builddir

Ninja的输出文件的目录(也可以存其他的构建的输出)。参阅上文更多细节中的 Ninja的log 或The Ninja build system (ninja-build.org)。

ninja_required_version

当前构建脚本所需的 Ninja 最低版本。参阅上文 版本兼容性 The Ninja build system (ninja-build.org)

规则变量

一个规则块包含影响规则处理的key = value声明列表。这里是特殊key 的完整列表:

command (必有的)

要运行的命令行。 每条规则只能有一个command声明。有关引用和执行多个command的更多详细信息,请参阅下一节。Ninja构建系统 (ninja-build.org)

depfile

包含额外隐式依赖项的可配置 Makefile 的路径。(参考下文或The Ninja build system (ninja-build.org))此功能明确支持C/C++头文件依赖,参考上文 C/C++ 头文件依赖 或 The Ninja build system (ninja-build.org)

deps

(自 Ninja 1.3 起可用。)如果存在,则一定是 gcc 或 msvc 之一,用来指定特殊依赖项的处理。(参考The Ninja build system (ninja-build.org)上文 C/C++ 头文件依赖 或The Ninja build system (ninja-build.org))生成的数据库作为 .ninja_deps 存储在 builddir 中(参考 builddir的描述)

msvc_deps_prefix

(自 Ninja 1.5 起可用。)定义应从 msvc 的 /showIncludes 输出中删除的字符串。 仅当 deps = msvc 并且未使用英文版 Visual Studio 时才需要。

description

命令的简短描述,用于在command运行时漂亮地打印command。 -v 标志控制是否打印完整command命令和其描述; 如果command失败,则一定会在command输出之前打印出完整的命令行。

dyndep

(自 Ninja 1.10 起可用。)仅在build语句中使用。 如果存在,必须命名指定一个build语句的输入。 将从文件中动态加载发现的依赖关系信息。 有关详细信息,请参阅下文动态依赖项部分。The Ninja build system (ninja-build.org)

generator

如果存在,则指定此规则用于重新调用生成器程序。 使用generator的rule构建的文件有两种特殊处理方式:首先,如果command发生变化,它们将不会被重新构建; 其次,默认情况下它们不会被清理。

in

以空格分隔的输入文件列表,作为引用此规则的build指令提供输入。在command里时将被shell引用。 (提供 $in 只是为了方便;如果您需要此输入文件列表的某些子集或变体,只需使用该输入列表构造一个新变量并使用它即可。)

in_newline

与 $in 相同,只是多个输入由换行符而不是空格分隔。 (与 $rspfile_content 一起使用;这解决了 MSVC 链接器中的一个错误,该错误是因为MSVC 链接器使用固定大小的缓冲区来处理输入。)

out

以空格分隔的输出文件列表,作为引用此规则的build指令提供输出,在command里时将被shell引用。

restat

如果存在,会让 Ninja 在执行command后重新统计command的输出。不会修改输出时间戳的command的每个输出文件都将被视为永远不需要构建。这可能会导致输出文件的反向依赖关系从挂起的构建操作列表中删除。

rspfile,rspfile_content

如果(两个都)存在,Ninja 将使用给定命令的响应文件,即在调用命令之前将所选字符串 (rspfile_content) 写入给定文件 (rspfile),并在成功执行命令后删除该文件.

这在 Windows 操作系统上特别有用,因为命令行的最大长度受到限制,有时候必须使用响应文件来代替。例如:

rule linkcommand = link.exe /OUT$out [usual link flags here] @$out.rsprspfile = $out.rsprspfile_content = $inbuild myapp.exe: link a.obj b.obj [possibly many other .obj files]

command变量的解释

从根本上来说,command行在 Unix 和 Windows 上的行为有所不同。

在 Unix 上,命令是参数数组。 Ninja 命令变量直接传递给 sh -c,然后由 sh -c 负责将该字符串解释为 argv 数组。 因此,引用规则是 shell 的引用规则,您可以使用所有正常的 shell 运算符,例如 && 来链接多个命令,或 VAR=value 命令来设置环境变量。

在 Windows 上,命令是字符串,因此 Ninja 将命令字符串直接传递给 CreateProcess。 (在简单执行编译器的常见情况下,这意味着开销更少。)因此,引用规则由被调用的程序确定,在 Windows 上通常由 C 库提供。 如果需要对命令进行 shell 解析(例如使用 && 链接多个命令),请通过在命令前添加命令标识  /c 来使命令执行 Windows shell。 Ninja 可能会出现“无效参数”错误,这通常表示已超出命令行长度。

构建的输出

有两种类型的构建输出,它们略有不同:

显式输出,和command中列出的一样。 这些输出是rule中的 $out 变量。这是要使用的标准输出形式,例如 编译command的object文件。

隐式输出,如加在build行中冒号( : )之前列出的语法 | out1 out2 (自 Ninja 1.7 起可用)。 语义与显式输出相同,唯一的区别是隐式输出不会显示在 $out 变量中。这是为了在当前command执行时不显示输出。

构建的依赖

构建依赖关系分为三种类型,它们略有不同。

显式依赖项,如comman行中列出的。 是 rule 中的 $in 变量。修改这些文件将导致重新构建输出,如果找不到这些文件并且ninja不知道如何构建这些文件,构建就会中止。这是要使用的标准依赖形式,例如 为源文件提供编译命令。

隐式依赖项,可以从规则上的 depfile 属性中获取,或在位于build行的末尾获取 | dep1 dep2 。 语义与显式依赖项相同,唯一的区别是隐式依赖项不会出现在 $in 变量中。这是为了不在命令的命令行上显示依赖关系。例如,对于一个用来 运行读取硬编码脚本 的规则,硬编码文件应该是隐式依赖项,因为该文件修改后也应该重新构建,即使它没显示在输入列表里。

请注意,通过 depfile 加载的依赖项具有稍微不同的语义,如上文 规则 中所述。

独立依赖项,在build行的末尾用 || dep1 dep2 表示。当他们过期时,在他们重新构建之前不会重新构建输出,但修改独立依赖项不会导致输出重新构建。独立依赖项对于引导尽在构建期间发现的依赖项十分有用。例如:在开始后续的编译步骤之前先生成头文件(一旦在编译过程中使用了这些头文件,生成的依赖文件将表示隐式依赖关系)

文件路径将按照相对路径和绝对路径进行比较,对于同一个文件,ninja认为这两个路径是不同的。

校验(Validations)

自 Ninja 1.11 起可用。

当build行是command行或default语法传递的依赖项之一时,build行上列出的校验项会使指定的文件被添加到构件图的顶层(就像在 Ninja 命令行上指定的一样)。

无论build语句的输出文件是否脏,验证都会添加到生成图中,并且输出用作验证的文件的生成语句的脏状态对请求它的生成语句中的脏状态没有影响。

原文:Validations are added to the build graph regardless of whether the output files of the build statement are dirty are not, and the dirty state of the build statement that outputs the file being used as a validation has no effect on the dirty state of the build statement that requested it.

笔者注:这句话翻译起来真恶心,翻译完了也不好理解。

build语句可以列出另一个build作为校验项,即使第二个build依赖于第一个build。

校验项旨在处理想执行错误检查但不想通过build生成任何生成物的规则,例如静态分析工具。将静态分析规则标记为源文件的主生成规则或依赖于主生成规则的规则的隐式输入将减慢生成的关键路径,但使用验证将允许生成在主生成规则完成后与静态分析规则并行进行。

变量的展开

变量将在路径中和 = 的右侧展开(build语法、default语法或name = value形式的语法)

当计算 name = value 语句时,变量在其右侧立即展开(根据规则的作用域),并且从那时起 $name 展开为静态字符串作为展开的结果。你永远不用“双重转义”来防止变量被展开两次。

所有变量在解析中遇到时都会立即展开,但有一个重要的例外:规则块中的变量在使用规则时展开,而不是在声明规则时展开。 在以下示例中,演示规则打印“this is a demo of bar”。

rule democommand = echo "this is a demo of $foo"build out: demofoo = bar

分析和范围界定

顶层变量声明的范围仅限于它们所在的文件。

规则声明的范围也限于它们出现的文件。(自 Ninja 1.6 起可用)

subninja 关键字用于包含另一个 .ninja 文件,引入了新的范围。 包含的 subninja 文件可以使用父文件中的变量和规则,并在文件范围内隐藏它们的值,但它不会影响父文件中变量的值。

要在当前作用域中包含另一个 .ninja 文件,就像 C #include 语句一样,请使用 include 而不是 subninja。

build块中缩进的变量声明的范围,仅限于该build块。 在build块中展开变量的完整查找顺序(规则也适用)是:

  1. 特殊的内置变量($in、$out)。
  2. build块中的构建层变量。
  3. rule块中的规则层变量(即 $command)。(注意根据上面的描述这里的展开会更晚,并且可以使用范围类的绑定如 $in)
  4. build指令所在的文件的文件层变量。
  5. 使用subninja关键字包含的文件中的文件层变量。

动态依赖关系

自 Ninja 1.10 起可用。

//TODO:剩最后一点下周在更

示例代码

这篇关于Ninja使用教程【含官方文档翻译】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898797

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

Toolbar+DrawerLayout使用详情结合网络各大神

最近也想搞下toolbar+drawerlayout的使用。结合网络上各大神的杰作,我把大部分的内容效果都完成了遍。现在记录下各个功能效果的实现以及一些细节注意点。 这图弹出两个菜单内容都是仿QQ界面的选项。左边一个是drawerlayout的弹窗。右边是toolbar的popup弹窗。 开始实现步骤详情: 1.创建toolbar布局跟drawerlayout布局 <?xml vers

C#中,decimal类型使用

在Microsoft SQL Server中numeric类型,在C#中使用的时候,需要用decimal类型与其对应,不能使用int等类型。 SQL:numeric C#:decimal

Steam邮件推送内容有哪些?配置教程详解!

Steam邮件推送功能是否安全?如何个性化邮件推送内容? Steam作为全球最大的数字游戏分发平台之一,不仅提供了海量的游戏资源,还通过邮件推送为用户提供最新的游戏信息、促销活动和个性化推荐。AokSend将详细介绍Steam邮件推送的主要内容。 Steam邮件推送:促销优惠 每当平台举办大型促销活动,如夏季促销、冬季促销、黑色星期五等,用户都会收到邮件通知。这些邮件详细列出了打折游戏、

探索Elastic Search:强大的开源搜索引擎,详解及使用

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引入 全文搜索属于最常见的需求,开源的 Elasticsearch (以下简称 Elastic)是目前全文搜索引擎的首选,相信大家多多少少的都听说过它。它可以快速地储存、搜索和分析海量数据。就连维基百科、Stack Overflow、

flask 中使用 装饰器

因为要完成毕业设计,我用到fountain code做数据恢复。 于是在github上下载了fountain code的python原代码。 github上的作者用flask做了fountain code的demo。 flask是面向python的一个网站框架。 里面有用到装饰器。 今天笔试的时候,我也被问到了python的装饰器。