Fuchsia 构建系统使用自定义 Ninja 二进制文件,该文件可为开发者体验带来多项改进。本页将介绍这些功能。
设计初衷
有关为 Fuchsia 自定义 Ninja 的动机,请参阅 RFC-0153。
简而言之,上游版本中很难获得的一些功能将使 Fuchsia 开发者受益匪浅。
所有 Fuchsia 特有的更改都在本地 Ninja Git 镜像的本地 fuchsia-rfc-0153
分支上执行,并定期进行变基,以便轻松地将它们作为 GitHub 拉取请求发送到上游项目,如 RFC 的策略部分中所述。
功能:正在运行的命令的状态
将环境中的 NINJA_STATUS_MAX_COMMANDS
设置为严格正整数,以便在智能终端中运行时,Ninja 可以在状态行下方打印运行时间最长的命令及其所用时间的表格。例如,使用 export NINJA_STATUS_MAX_COMMANDS=4
时,状态可能如下所示:
[0/28477](260) STAMP host_x64/obj/tools/configc/configc_sdk_meta_generated_file.stamp
0.4s | STAMP obj/sdk/zircon_sysroot_meta_verify.stamp
0.4s | CXX obj/BUILD_DIR/fidling/gen/sdk/fidl/fuchsia.me...chsia.media/cpp/fuchsia.media_cpp_common.common_types.cc.o
0.4s | CXX obj/BUILD_DIR/fidling/gen/sdk/fidl/fuchsia.me...fuchsia.media/cpp/fuchsia.media_cpp.natural_messaging.cc.o
0.4s | CXX obj/BUILD_DIR/fidling/gen/sdk/fidl/fuchsia.me...dia/cpp/fuchsia.media_cpp_natural_types.natural_types.cc.o
以下动画图片展示了实际效果:
请注意:
在 Ninja 的试运行或详细调用(即使用
-n
或--verbose
标志)中,此功能会自动停用。当 Ninja 未在交互式 / 智能终端中运行时,此功能会自动停用。
运行控制台命令时,此功能也会暂停(在上面的示例中运行 Bazel 操作时可以看到)。
借助此功能,您可以轻松直观地了解 build 中的瓶颈,即阻止其他命令并行运行的长时间运行的命令。
默认情况下,命令表每秒更新 10 次,这对于了解哪些长时间运行的命令会阻碍 build 过程非常有用。您可以将 NINJA_STATUS_REFRESH_MILLIS
设置为以毫秒为单位的十进制值,从而更改刷新周期(不过,由于经过的时间仅打印到一位小数,因此低于 100 的任何值都会被忽略)。
功能:支持 GNU Make Jobserver
GNU Make Jobserver 协议允许构建系统在任何时间点限制并发作业(即线程或进程)的总数,即使存在递归构建工具调用也是如此。
它需要一个顶级服务器来设置一个由参与的客户端(例如编译器、链接器,甚至构建工具)共享的作业槽池。
Fuchsia 特定的 Ninja 二进制文件既可以充当协议的客户端,也可以充当协议的服务器。
您可以在启动 Ninja 时通过 --jobserver
命令行标志或在环境中设置 NINJA_JOBSERVER=1
来启用服务器模式。
当 Ninja 启动时,它会查看 MAKEFLAGS
环境变量的值,并自动启用客户端模式。当从充当服务器的不同 build 调用 Ninja 时,此功能非常有用。
在 Fuchsia build 中,在 args.gn
中设置 enable_jobserver = true
可让顶级 Ninja 调用以服务器模式启动。
例如,它已针对核心 IDK 和核心 SDK 构建器配置设置,可节省 6 到 12 分钟的构建时间。因为这些需要从顶级 build 启动 24 个以上的 Ninja 子 build,而这些子 build 可以利用该协议更好地协调它们各自如何生成多个并行命令。
功能:以 Chrome Trace JSON 数组格式生成 build 轨迹
--chrome_trace FILENAME
选项可用于告知 Ninja 在构建完成后(即使在失败的情况下)生成构建事件的轨迹。
建议在输出 FILENAME
中使用 .gz
后缀,以直接生成 gzip 压缩的轨迹文件,因为这些文件通常要小 20 倍。
该文件采用 Chrome Trace JSON Array 格式,可以直接加载到任何基于 Chromium 的浏览器的 chrome://tracing
标签页中,更有趣的是,还可以通过 https://ui.perfetto.dev
加载,后者还支持将压缩的轨迹作为输入进行读取。
请注意,生成的轨迹文件还包含有助于直观呈现 build 关键路径的流事件。相应 build 事件的 cat
字段的值为 critical_path
。
功能:持久模式,可缩短启动时间
通过在环境中设置 NINJA_PERSISTENT_MODE=1
来加快后续 Ninja 调用速度。此功能使 Ninja 启动后台服务器进程来读取一次 build 清单,然后在连续 build 之间将 build 图保留在内存中。
请注意:
此功能应完全透明,不应以其他方式影响 Ninja 的行为。如果您发现任何问题或差异,请发送电子邮件至
fuchsia-build-team@google.com
告知我们!系统会自动检测输入
.ninja
文件的任何更改。在这种情况下,系统会关闭现有服务器,并自动启动新服务器。更改 GN build 文件或执行jiri update
后,无需进行额外的用户互动。服务器进程在空闲 5 分钟后将正常关闭。 在您的环境中设置
NINJA_PERSISTENT_TIMEOUT_SECONDS=<count>
即可更改此延迟时间。使用
fx build -t server status
检索当前 build 目录的服务器状态。使用
fx build -t server stop
显式停止服务器的任何正在运行的实例。设置
NINJA_PERSISTENT_LOG_FILE=<path>
以将与持久模式相关的日志发送到指定的文件路径。对于
core.x64
build 配置,每个服务器进程目前大约需要 1 GiB 的 RAM。确切的数字将取决于 Ninja 图的大小,而这取决于您的args.gn
配置。每个 Ninja build 目录最多只能由一个服务器进程提供服务。不过,如果使用多个 build 目录,则可能会有多个进程。
忍者工具(例如
ninja -C <dir> -t commands <target>
)尚未在服务器上运行,因此仍会使用缓慢的启动。我们会在未来修复此问题,以加快查询速度。
已知 bug / 注意事项(将解决):
目前,在同一目录下混合使用持久 build 和非持久 build 可能会使服务器感到困惑,因为对 Ninja build 和依赖项日志的独立更改无法得到正确检测。此问题将会得到解决。
解决方法:在环境中取消设置
NINJA_PERSISTENT_MODE
之前,使用-t server stop
停止服务器。“快速启动”需要几秒钟的时间。目前,每个增量 build 仍需要对 build 图中的所有文件调用 stat(),这目前需要几秒钟的时间。未来,我们将使用基于 inotify / kqueue 的主机操作系统文件系统监控功能来解决此问题,以便在仅修改了少量文件时立即开始。
目前不适用于 Windows。这是因为存在技术 Win32 限制,该限制会阻止将控制台句柄复制到其他进程。这主要是上游 Ninja 团队的问题,因为 Fuchsia 开发不在 Windows 上进行。