完全指南:统一构建与本地调试工作流)
Flutter Engine 开发工具 etEngine Tool完全指南统一构建与本地调试工作流【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter导读本文基于 engine/src/flutter/tools/engine_tool/README.md 展开系统讲解 Flutter 引擎仓库中命令行工具etengine tool的设计初衷与全部用法。et面向在 engine 源码中改一行、编一次、跑一个测试的高频迭代场景将此前分散的 GN/Ninja 构建、测试、格式化、lint、本地运行等操作收敛为统一命令接口。读完本文你将掌握如何配置环境并理解构建配置build configuration这一核心抽象、如何构建 host/target 引擎与指定 GN 目标、如何运行 C 测试、如何用本地引擎产物直接运行 Flutter App以及 RBE 远程构建、自定义引擎配置、输出目录清理等高级能力。一、et是什么etengine tool是一个用 Dart 编写的命令行工具其目标是为构建并开发 Flutter engine提供统一接口。它解决的核心痛点在于engine 构建依赖大量 GN 参数、平台工具链与 CI 配置手工记忆并拼装这些命令既易错又难以复用而et将这些复杂性封装为语义化的子命令build、test、format、lint、run等。从入口源码看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 的x64与arm64。将et加入 PATHREADME 建议将引擎自带的bin目录加入PATHPATH$PATH:/path/to/engine/flutter/bin这里的/path/to/engine/flutter/bin即当前仓库中的 engine/src/flutter/bin 目录内含et与et.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 engines 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 的注册代码可知内部还实现了CleanupCommand与StampCommand。全局选项仅有两个-h/--help与-v/--verbose其中-v在 main.dart 中会把日志级别切到Logger.infoLevel输出更详细的过程信息。二、核心抽象构建配置build configurationet的许多命令都围绕一个构建配置展开通常用--config简写-c显式指定。一个构建配置至少包含三要素要素字段含义可运行平台drone_dimensions该构建可运行在哪些CI机器维度上编译期标志gn传给 GN 生成工具的参数决定构建行为名称与说明name、description人类可读的配置名与描述以 engine/src/flutter/ci/builders/local_engine.json 中的一个真实条目为例可以看到一个完整配置包含drone_dimensions、gn如--ios、--runtime-mode debug、--no-stripped、--no-lto、--rbe等、ninja.config对应输出目录名与description等字段。配置的存放位置与命名解析构建配置通常定义在 engine/src/flutter/ci/builders 下分两类CI 任务专用配置为某个 CI 任务而建构建并跑测试例如 mac_unopt.json、linux_unopt.json、linux_host_engine.json 等仅用于本地开发与迭代的配置集中在 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_debughost 引擎适用于以下场景想脱离具体设备/平台独立测试、调试或迭代某个功能正在开发当前桌面平台特有的功能想组合 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对改动过的文件运行全部 formatteret format但有时某个依赖变更或工具自身变更会使你并未改动过的文件处于 dirty 状态无法通过格式检查此时需要检查全部文件# 检查 *所有* 文件这会 *慢得多* et format --all对应的命令实现位于 format_command.dart测试位于 test/commands/format_command_test.dart。3.6 运行 linter与 formatter 类似可用et lint运行仓库级 linteret 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 runcd to/project/dir et run[!NOTE]et run会按需重建host 与 target 构建耗时可能相当可观。实现层面et run通过 flutter_tool 互操作层与本地 Flutter 工具协作完成设备探测与启动可参考 lib/src/flutter_tool_interop/ 下的flutter_tool.dart、device.dart、target_platform.dart对应测试为 test/commands/run_command_test.dart。四、高级特性Advanced Features以下功能可能仅面向部分 engine 团队或上游用户例如 Dart VM/SDK 团队的开发者其完善程度与易用性相对常见任务可能略逊。4.1 启用远程构建执行RBEGoogle 员工可选择RBEremote build execution来大幅加速构建一方面复用此前构建并被缓存的产物另一方面把编译任务委托给高性能远程虚拟机。启用方式参考外部文档README 所指向的flutter.dev/to/engine-rbe。启用后默认情况下et构建会尽量使用 RBE这同时也意味着构建隐式依赖活跃的网络连接。可通过--build-strategy在单次命令内临时切换偏好远程还是纯本地# 纯本地构建某些增量构建反而更快无需联网 et build --build-strategylocal # 纯远程构建对本机负载更小需要高速网络 et build --build-strategyremote如果希望彻底关闭RBE已启用的情况下可使用--no-rbeet build --no-rbe[!CAUTION] 关闭 RBE 会使构建上下文失效——即此前在启用 RBE 时构建出的产物不会被复用。除非你在调试工具本身或 RBE 配置否则更推荐用--build-strategylocal代替--no-rbe。4.2 运行 Dart 测试et对运行Dart单元测试提供有限支持et test //flutter/tools/engine_tool/...[!NOTE] 与 C 不同目前 Dart 测试不要求声明BUILD.gntarget且绝大多数 Dart 包也没有声明随着 GN 在 Dart 侧被更广泛采用该命令会越来越通用。这一点在本仓库中也能得到印证整个 tools/engine_tool 的 Dart 测试test/ 目录下二十余个*_test.dart并不需要逐一登记进 GN 即可通过et test运行。4.3 使用自定义引擎配置绝大多数情况下应使用预置配置它们经过 CI 验证但当你需要构建一个尚未预置的配置时README 给出了两步决策清单我的配置是否代表一组应当在 CI 上测试、或值得他人复用的标志组合如果是最佳做法是把该构建加入 engine/src/flutter/ci/builders——既可作为 CI 构建也可仅作为 local_engine.json 中的本地引擎构建。这样该构建对其它开发者可复现、有文档并能被et命令行自动识别。我的配置仅用于一次性测试或验证如果是可以通过--gn-args追加任意GN 参数即本来会由 tools/gn 解析的那些参数通常配合某个现成配置模板一起使用。例如启用链接期优化LTOet 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-since2024-01-01从命名看--dry-run是安全预览开关--untouched-since接受一个日期值示例中2024-01-01表示删除 2023 年及以前访问过的目录。该命令的实现与测试位于 cleanup_command.dart 和 test/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-toollabel 的 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运行全仓库 linteret lint用本地引擎产物运行 Appet run在 App 工程目录下纯本地 / 纯远程构建单次et build --build-strategylocal/--build-strategyremote关闭 RBE慎用et build --no-rbe追加 GN 参数的一次性构建et build --config cfg --gn-args--no-prebuilt-dart-sdk删除 30 天以上未访问输出目录et cleanup可用--dry-run预览、--untouched-sincedate自定义阈值运行 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 的配置样例入手。【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考