首页
/ Flutter Engine 开发工具 et(Engine Tool)完全指南:统一构建与本地调试工作流

Flutter Engine 开发工具 et(Engine Tool)完全指南:统一构建与本地调试工作流

2026-09-07 11:54:55作者:管翌锬

导读

本文基于 engine/src/flutter/tools/engine_tool/README.md 展开,系统讲解 Flutter 引擎仓库中命令行工具 et(engine tool) 的设计初衷与全部用法。et 面向在 engine 源码中"改一行、编一次、跑一个测试"的高频迭代场景,将此前分散的 GN/Ninja 构建、测试、格式化、lint、本地运行等操作收敛为统一命令接口。读完本文,你将掌握:如何配置环境并理解"构建配置(build configuration)"这一核心抽象、如何构建 host/target 引擎与指定 GN 目标、如何运行 C++ 测试、如何用本地引擎产物直接运行 Flutter App,以及 RBE 远程构建、自定义引擎配置、输出目录清理等高级能力。


一、et 是什么

et(engine tool)是一个用 Dart 编写的命令行工具,其目标是为"构建并开发 Flutter engine"提供统一接口。它解决的核心痛点在于:engine 构建依赖大量 GN 参数、平台工具链与 CI 配置,手工记忆并拼装这些命令既易错又难以复用,而 et 将这些复杂性封装为语义化的子命令(buildtestformatlintrun 等)。

从入口源码看,et 的执行链非常清晰:

  • 仓库内启动脚本 engine/src/flutter/bin/et(以及 Windows 版 et.bat)根据 uname 探测当前平台(linux/macos × x64/arm64),定位引擎自带的 Dart SDK(${ENGINE_DIR}/prebuilts/.../dart-sdk),再调用 Dart 入口 engine/src/flutter/tools/engine_tool/bin/et.dart。若 tools/engine_tool/.dart_tool 不存在,脚本会直接提示 "You must run 'gclient sync -D' before using this tool."——即工具只能在完成依赖同步的合法仓库中运行。
  • Dart 入口 lib/main.dart 会调用 Engine.findWithin(...) 向上查找 engine 仓库根目录,随后加载 ci/builders 目录下的全部构建配置;若未找到任何构建配置或配置解析出错,直接报错退出
  • 最后由 lib/src/commands/command_runner.dart 中的 ToolCommandRunner 注册并派发所有子命令。

适用前提

  • 具备 Flutter framework 与 engine 的基础知识(如架构分层);
  • 已获得一份合法且同步完毕的 engine 源码检出,并满足 engine 开发环境搭建文档 的要求(该文档对应 README 中引用的 external 链接,仓库内同步维护于 docs/engine/contributing 目录);
  • 运行平台受支持(从启动脚本可看出仅支持 Linux/macOS 的 x64arm64)。

et 加入 PATH

README 建议将引擎自带的 bin 目录加入 PATH

PATH=$PATH:/path/to/engine/flutter/bin

这里的 /path/to/engine/flutter/bin 即当前仓库中的 engine/src/flutter/bin 目录(内含 etet.bat 两个启动脚本)。

验证安装:et help

$ et help
A command line tool for working on the Flutter Engine.

This is a community supported project, file a bug or feature request:
https://flutter.dev/to/engine-tool-bug.

Usage: et <command> [arguments]

Global options:
-h, --help       Print this usage information.
-v, --verbose    Prints verbose output

Available commands:
  build    Builds the engine
  fetch    Download the Flutter engine's dependencies
  format   Formats files using standard formatters and styles.
  lint     Lint the engine repository.
  query    Provides information about build configurations and tests.
  run      Run a Flutter app with a local engine build.
  test     Runs a test target

Run "et help <command>" for more information about a command.

从帮助信息可以看到全部 7 个公开子命令;此外从 command_runner.dart 的注册代码可知,内部还实现了 CleanupCommandStampCommand。全局选项仅有两个:-h/--help-v/--verbose(其中 -vmain.dart 中会把日志级别切到 Logger.infoLevel,输出更详细的过程信息)。


二、核心抽象:构建配置(build configuration)

et 的许多命令都围绕一个 构建配置 展开,通常用 --config(简写 -c)显式指定。一个构建配置至少包含三要素:

要素 字段 含义
可运行平台 drone_dimensions 该构建可运行在哪些(CI)机器维度上
编译期标志 gn 传给 GN 生成工具的参数,决定构建行为
名称与说明 namedescription 人类可读的配置名与描述

engine/src/flutter/ci/builders/local_engine.json 中的一个真实条目为例,可以看到一个完整配置包含 drone_dimensionsgn(如 --ios--runtime-mode debug--no-stripped--no-lto--rbe 等)、ninja.config(对应输出目录名)与 description 等字段。

配置的存放位置与命名解析

构建配置通常定义在 engine/src/flutter/ci/builders 下,分两类:

  1. CI 任务专用配置:为某个 CI 任务而建(构建并跑测试),例如 mac_unopt.jsonlinux_unopt.jsonlinux_host_engine.json 等;
  2. 仅用于本地开发与迭代的配置:集中在 local_engine.json,例如上例中的 macos/ios_debug

--config 对配置名的解析规则与"是否带 ci/ 前缀"有关。仍以本地 debug 为例:

# 带前缀:隐式引用 ci/builders/<对应任务文件>.json
et build --config ci/host_debug_unopt_arm64

# 不带前缀:隐式引用 ci/builders/local_engine.json
et build --config host_debug_unopt_arm64

也就是说,et build --config host_debug_unopt_arm64 会自动去 local_engine.json 中查找名为 host_debug_unopt_arm64(该文件中通常写作 <os>/host_debug_unopt_arm64 形式,引用时省略平台前缀)的配置;而 ci/host_debug_unopt_arm64 则指向 CI 任务文件。

磁盘占用警告

[!CAUTION] 每个构建配置(也称一个 variant)会在 $ENGINE/src/out 下生成不同的输出目录,例如 $ENGINE/src/out/host_debug。这些输出动辄数 GB,且会快速累积。建议用 et cleanup(见下文"回收旧的输出目录")自动删除过期的输出目录。

name/description 还会进入 et query 等命令的索引,为开发者提供构建配置与测试的查询能力。


三、常见任务(Common Tasks)

这一部分面向绝大多数 engine 贡献者与使用者,是最常用的操作。

3.1 构建 host 引擎

host 引擎指运行在当前桌面操作系统上的引擎变体。例如在 ARM64 macOS 笔记本上构建 ARM64 macOS 桌面引擎,或在 x64 Linux 桌面上构建 x64 Linux 桌面引擎。

# 构建当前平台(host)的 debug 构建
et build

# 与上面等价(显式指定配置)
et build --config host_debug

host 引擎适用于以下场景:

  • 脱离具体设备/平台,独立测试、调试或迭代某个功能;
  • 正在开发当前桌面平台特有的功能;
  • 想组合 host 引擎与 target 引擎来 运行 Flutter App

3.2 构建 target 引擎

target 引擎指并非原生运行于当前桌面类操作系统、而是面向其它目标平台的引擎,例如 Android 或 iOS。例如在 macOS 上,可以构建 iOS 模拟器或真机引擎:

# 构建 iOS 真机(非模拟器)引擎
et build --config ios_debug

# 构建 iOS 模拟器引擎
et build --config ios_debug_sim

命名约定:target 引擎的配置名不带 host 前缀(而 host 引擎带 host_,如 host_debug)。target 引擎适用于:

  • 正在开发特定(目标)平台的功能;
  • 想组合 host 引擎与 target 引擎来 运行 Flutter App

这与 local_engine.json 中的条目相印证——例如 macos/ios_debug 的 description 即 "Builds a debug mode engine that targets iOS from a macOS host.",其 gn 参数包含 --ios --runtime-mode debug

3.3 构建指定 GN 目标

默认情况下 et build 构建整个引擎。例如下面两条命令等价:

et build --config host_debug

et build --config host_debug //flutter/...

尽管缓存通常能避免重建未变化的部分,但有时你比依赖树更清楚两次改动之间到底需要重编什么。此时可通过 et build 后追加目标参数,用 GN target 的全限定路径指定要构建的精确目标:

# 只构建 "flutter.jar" 这一个产物
et build --config android_debug_unopt_arm64 //flutter/shell/platform/android:android_jar

此外还支持两种"批量化"写法:

# 递归构建 //flutter/shell/platform 目录下的所有目标
et build --config android_debug_unopt_arm64 //flutter/shell/platform/...

# 非递归构建该目录下的全部目标(仅此一层)
et build --config android_debug_unopt_arm64 //flutter/shell/platform:all

语法要点归纳:

目标写法 含义
//path/to:target 精确到单个 GN 目标
//path/to/dir/... 递归构建该目录下所有目标
//path/to/dir:all 非递归地构建该目录内全部目标(不含子目录)

3.4 运行 C++ 测试

et test 可以同时重建并运行 C++ 单元测试:

et test //flutter/impeller:impeller_unittests

同样支持 /...:all 两种批量写法。et test 的定位在源码中有对应实现(test_command.dart),其测试覆盖可见 test/commands/test_command_test.dart

[!NOTE] 对非 C++ 测试的支持有限,参见下文 运行 Dart 测试

3.5 运行格式化工具(formatters)

改动过的文件运行全部 formatter:

et format

但有时某个依赖变更(或工具自身变更)会使你并未改动过的文件(处于 dirty 状态)无法通过格式检查,此时需要检查全部文件:

# 检查 *所有* 文件,这会 *慢得多*!
et format --all

对应的命令实现位于 format_command.dart,测试位于 test/commands/format_command_test.dart

3.6 运行 linter

与 formatter 类似,可用 et lint 运行仓库级 linter:

et lint

截至本文所依据的文档版本,linter 总是对全仓库运行。实现见 lint_command.dart 与其测试 test/commands/lint_command_test.dart

3.7 使用本地引擎构建运行 Flutter App

通常情况下,用预构建引擎运行 Flutter 应用的方式是:

cd to/project/dir
flutter run

而当你在迭代 engine 源码时,更希望用上面刚构建出的 engine 产物(host 与 target 都有)来运行应用,此时用 et run

cd to/project/dir
et run

[!NOTE] et run按需重建 host 与 target 构建,耗时可能相当可观。

实现层面,et run 通过 flutter_tool 互操作层与本地 Flutter 工具协作完成设备探测与启动(可参考 lib/src/flutter_tool_interop/ 下的 flutter_tool.dartdevice.darttarget_platform.dart),对应测试为 test/commands/run_command_test.dart


四、高级特性(Advanced Features)

以下功能可能仅面向部分 engine 团队或上游用户(例如 Dart VM/SDK 团队的开发者),其完善程度与易用性相对常见任务可能略逊。

4.1 启用远程构建执行(RBE)

Google 员工可选择 RBE(remote build execution) 来大幅加速构建:一方面复用此前构建并被缓存的产物,另一方面把编译任务委托给高性能远程虚拟机。

启用方式:参考外部文档(README 所指向的 flutter.dev/to/engine-rbe)。启用后,默认情况下 et 构建会尽量使用 RBE,这同时也意味着构建隐式依赖活跃的网络连接

可通过 --build-strategy单次命令内临时切换"偏好远程"还是"纯本地":

# 纯本地构建;某些增量构建反而更快;无需联网
et build --build-strategy=local

# 纯远程构建;对本机负载更小;需要高速网络
et build --build-strategy=remote

如果希望彻底关闭 RBE(已启用的情况下),可使用 --no-rbe

et build --no-rbe

[!CAUTION] 关闭 RBE 会使构建上下文失效——即此前在启用 RBE 时构建出的产物不会被复用。除非你在调试工具本身或 RBE 配置,否则更推荐用 --build-strategy=local 代替 --no-rbe

4.2 运行 Dart 测试

et 对运行 Dart 单元测试提供有限支持:

et test //flutter/tools/engine_tool/...

[!NOTE] 与 C++ 不同,目前 Dart 测试不要求声明 BUILD.gn target,且绝大多数 Dart 包也没有声明;随着 GN 在 Dart 侧被更广泛采用,该命令会越来越通用。

这一点在本仓库中也能得到印证:整个 tools/engine_tool 的 Dart 测试(test/ 目录下二十余个 *_test.dart)并不需要逐一登记进 GN 即可通过 et test 运行。

4.3 使用自定义引擎配置

绝大多数情况下应使用预置配置(它们经过 CI 验证),但当你需要构建一个尚未预置的配置时,README 给出了两步决策清单:

  1. 我的配置是否代表一组应当在 CI 上测试、或值得他人复用的标志组合? 如果是,最佳做法是把该构建加入 engine/src/flutter/ci/builders——既可作为 CI 构建,也可仅作为 local_engine.json 中的本地引擎构建。这样该构建对其它开发者可复现、有文档,并能被 et 命令行自动识别。

  2. 我的配置仅用于一次性测试或验证? 如果是,可以通过 --gn-args 追加任意 GN 参数(即本来会由 tools/gn 解析的那些参数),通常配合某个现成配置模板一起使用。

例如启用链接期优化(LTO):

et build --config host_release --lto

例如使用从源码构建的 Dart SDK(常被 Dart SDK/VM 开发者使用):

et build --config host_debug --gn-args="--no-prebuilt-dart-sdk"

[!TIP] 关于构建配置的更多信息,参见 engine/src/flutter/ci/builders/README.md

4.4 回收旧的输出目录

et cleanup 会删除长期未被访问的输出目录,默认阈值为最近 30 天,可用 --untouched-since 自定义。强烈建议先用 dry-run 预览将要删除的内容:

# 删除所有超过 30 天未访问的输出目录
et cleanup

# 预览:显示上面命令会删除哪些目录(实际不删)
et cleanup --dry-run

# 删除所有最后访问时间早于 2024-01-01 的输出目录
et cleanup --untouched-since=2024-01-01

从命名看,--dry-run 是安全预览开关,--untouched-since 接受一个日期值(示例中 2024-01-01 表示删除 2023 年及以前访问过的目录)。该命令的实现与测试位于 cleanup_command.darttest/commands/cleanup_command_test.dart,配合前面"输出目录可达数 GB"的警告,这是每个长期本地构建者都应养成的磁盘卫生习惯。


五、工程架构与测试约定(Contributing 指南精华)

et 欢迎社区贡献,README 中的开发约定(连同 contributing 相关规范)值得任何想为 engine_tool 提交代码的开发者遵守:

  • 遵循 Flutter 风格指南 中适用于 framework 仓库之外 Dart 代码的部分;其中包含超出纯代码格式的约定,未来即使改用 dart format 也会继续遵守。
  • main.dart 外,禁止直接调用 dart:io,只能通过 Environment 对象访问系统。这一点与源码结构严格对应:唯一直接 import 'dart:io' 的是 lib/main.dart(它构造 environment.dart 中的 Environment),其余代码均经由该对象与宿主系统交互。
  • 所有命令都必须有单元测试;若某些功能需要 fake 实现,就写 fake 实现。这正是 test/commands/ 下每个子命令都对应一个 *_test.dart 的原因。
  • 新增或修改功能时,同步更新本 README
  • Begin with the end in mind:从"该工具应提供的接口"出发设计,再反过来改造底层脚本与工具以提供支撑 API。

运行测试(用 et 自举):

et test //flutter/tools/engine_tool/...

如果不知道从何下手,可以关注仓库中标有 e: engine-tool label 的 issue。


六、总结:一张 et 速查表

意图 命令
查看帮助与所有子命令 et help / et help <command>
构建当前平台 host debug 引擎 et build / et build --config host_debug
构建 target(如 iOS)引擎 et build --config ios_debug / et build --config ios_debug_sim
只构建某个 GN 目标 et build --config <cfg> //path/to:target
递归/非递归构建目录目标 et build --config <cfg> //dir/...//dir:all
重建并运行 C++ 测试 et test //flutter/impeller:impeller_unittests
格式化改动文件 / 全部文件 et format / et format --all
运行全仓库 linter et lint
用本地引擎产物运行 App et run(在 App 工程目录下)
纯本地 / 纯远程构建(单次) et build --build-strategy=local / --build-strategy=remote
关闭 RBE(慎用) et build --no-rbe
追加 GN 参数的一次性构建 et build --config <cfg> --gn-args="--no-prebuilt-dart-sdk"
删除 30 天以上未访问输出目录 et cleanup(可用 --dry-run 预览、--untouched-since=<date> 自定义阈值)
运行 engine_tool 自身的 Dart 测试 et test //flutter/tools/engine_tool/...

et 的价值在于把"查找构建配置、拼装 GN 参数、驱动 ninja、管理测试与产物"这套引擎开发高频动作,收敛为一份配置(ci/builders 下的 JSON)+ 一组语义命令的稳定接口。无论你是偶尔编译一次 host debug 引擎、还是长期迭代 Impeller 或 Android shell 的 engine 开发者,掌握 et 都能显著缩短"改动 → 验证"的反馈回路;而其"配置即代码、全部命令有测试、系统访问一律走 Environment"的工程约束,也为后续维护者提供了一套清晰可循的质量基线。继续深挖实现细节,可从 engine/src/flutter/tools/engine_tool/lib/src/commands/ 的各个子命令源码与 engine/src/flutter/ci/builders 的配置样例入手。

登录后查看全文
热门项目推荐
相关项目推荐