news 2026/10/15 2:53:58

Flutter Engine RBE 远程构建指南:在 flutter_flutter 仓库中配置并使用 Remote Build Execution 加速引擎编译

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter Engine RBE 远程构建指南:在 flutter_flutter 仓库中配置并使用 Remote Build Execution 加速引擎编译
  • 跨平台
  • 前端
  • 移动开发
  • OpenHarmony

【免费下载链接】flutter_flutter

本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。

项目地址:https://gitcode.com/CPF-Flutter/flutter_flutter
点击查看免费下载

本文围绕 flutter_flutter 仓库中 engine/src/flutter/docs/rbe/rbe.md 的官方文档展开,系统讲解如何在构建 Flutter Engine 时启用 RBE(Remote Build Execution,远程构建执行)。文章将带你完成.gclient配置、CIPD/gcloud 双重认证、通过et工具发起 RBE 构建、按需禁用 RBE 与 LTO,并深入解读仓库中 DEPS、et工具与构建配置 JSON 的底层实现,最后给出完整的故障排查手段,帮助你真正上手"本地开发、远端编译、缓存复用"的高效引擎构建工作流。

适用范围与前置条件

在动手之前必须先明确:根据官方文档 rbe.md 的说明,这套 RBE 方案预期仅对 Google 内部员工(Googlers)在 corp Linux、macOS 和 Windows 主机(含 cloudtop 实例)上可用。原因在于 RBE 的配置文件存放在受权限管控的flutter_internalCIPD bucket 中,需要 Googler 身份的 CIPD 认证才能拉取。

从仓库源码看,这一限制体现在两处:

  • 根目录 DEPS 中use_rbe变量默认值为False,并注释明确写道:"When this is true, the Flutter Engine's configuration files and scripts for RBE will be downloaded from CIPD. This option is only usable by Googlers."(该选项仅 Googlers 可用)。
  • 引擎工具的源码 environment.dart 中,hasRbeConfigInTree()通过检查engine/src/flutter/build/rbe目录是否存在来判断"当前环境是否支持远程构建",而该目录正是由上述 CIPD 依赖在gclient sync时按需下载的。

对于非 Googler 的开发者(包括基于本仓库进行 OpenHarmony 适配的开发者),RBE 部分可能无法直接使用,但本文中关于.gclient的custom_vars结构、et构建工具的用法、GN/Ninja 构建参数以及local_engine.json的自定义方式,仍然适用于常规的本地引擎构建,值得完整阅读。

快速开始:在.gclient中启用 RBE

第一步:编辑.gclient文件

启用 RBE 的第一步是在仓库根目录的.gclient文件中,于custom_vars一节加入"use_rbe": True。官方文档给出的完整示例为:

solutions = [ { "managed": False, "name": "src/flutter", "url": "git@github.com:zanderso/engine.git", "custom_deps": {}, "custom_vars": { "use_rbe": True, }, "deps_file": "DEPS", "safesync_url": "", }, ]

各字段含义:

字段说明
managed是否由 gclient 管理该 solution 的版本,引擎通常设为False
namesolution 在本地的目录名(引擎通常为src/flutter)
url引擎源码仓库地址,替换为你实际使用的仓库即可
custom_deps附加依赖项,通常为空对象
custom_vars传递给 DEPS 解析的变量,use_rbe: True即在此处声明
deps_filegclient 依赖描述文件,即根目录的DEPS
safesync_url安全同步地址,本地开发通常留空

在 flutter_flutter 仓库中,OpenHarmony 适配版本的 gclient 配置模板位于 engine/scripts/ohos.gclient,其 solution 结构与上例完全一致(custom_deps、deps_file、managed、name、safesync_url、url字段一一对应),只是deps_file指向DEPS_ohos,url指向 OpenHarmony 镜像仓库。可以看到custom_vars正是这类"按需开关依赖下载"的标准挂载点——原文档中下载 web 引擎所需 emsdk 也是通过取消注释该处的custom_vars来实现。

第二步:CIPD 认证

完成上述编辑后,必须以 Googler 身份通过 CIPD 认证,以便从flutter_internalCIPD bucket 下载 RBE 配置:

cipd auth-login

这一步对应到源码层面,就是让gclient sync能够以合法身份解析 DEPS 中声明的两个关键 CIPD 依赖组:

  1. reclient 二进制(infra/rbe/client/${{platform}}):按主机平台(linux-x64、mac-arm64、mac-x64、windows-x64)分别下载到engine/src/flutter/buildtools/<平台>/reclient目录,版本由 DEPS 中的reclient_version变量(当前为git_revision:29a9d3cb597b6a7d67fa3e9aa8a7cab1c81232ee)决定;
  2. RBE 配置(flutter_internal/rbe/reclient_cfgs):下载到engine/src/flutter/build/rbe目录,这正是et工具判断"当前环境是否支持 RBE"的目录。

其中 Windows 平台的 reclient 依赖条件还额外要求download_windows_deps为真,Linux/macOS 则分别以host_os+host_cpu组合作为condition。

第三步:执行gclient sync -D

认证成功后,运行:

gclient sync -D

-D参数会删除未在 DEPS 中声明、或不再需要的本地依赖,确保工作区状态与依赖声明严格一致。执行完毕后,engine/src/flutter/build/rbe与engine/src/flutter/buildtools/<平台>/reclient应已就位,et工具即可识别当前环境支持 RBE。

运行 RBE 构建:统一经由et工具

为什么必须使用et

官方文档明确规定:引擎仓库中所有 RBE 构建都必须通过et工具发起,其入口脚本是//flutter/bin/et。原因在于et会在ninja调用前后正确地初始化与关闭本地 RBE proxy(reproxy)——如果绕过et直接调用ninja,RBE 的本地代理生命周期无人管理,构建必然失败。

从仓库源码看,engine/src/flutter/bin/et 是一个 Bash 入口脚本:它根据uname -s/uname -m判定宿主机平台(linux/macos×arm64/x64),拼接出平台名后调用对应预编译 Dart SDK 执行tools/engine_tool/bin/et.dart;若发现tools/engine_tool/.dart_tool目录不存在,会提示你"必须先运行gclient sync -D"。Windows 上对应的是 engine/src/flutter/bin/et.bat。

gcloud 认证:绑定 RBE worker pool 所在项目

运行 RBE 构建前,还必须通过gcloudSDK 认证到拥有 RBE worker pool 的 Google Cloud 项目:

gcloud init --project flutter-rbe-prod

macOS 上有一个易踩的坑:运行gcloud前必须确保python3在 PATH 中且不来自 homebrew 等第三方来源,which python3应返回/usr/bin/python3,否则可能引发认证相关异常。

若bootstrap报错找不到Application Default Credentials(应用默认凭据),则执行:

gcloud auth application-default login

列出可用构建

et工具可用的构建由//flutter/ci/builders目录下的构建配置 JSON 文件决定。查看命令:

et help build

只列出适合本地开发的构建;要查看全部构建:

et help build --verbose

verbose 列表中带ci/或ci\前缀的构建,正是 CI 上以完全相同 GN 参数与 Ninja 目标运行的构建,可用于本地复现 CI 行为。

这一行为的源码实现在 build_plan.dart:configureArgParser会读取当前平台可运行的构建配置,非 verbose 模式下隐藏ci/前缀配置以缩短帮助文本;--config(缩写-c)参数会校验输入是否为合法构建名。

运行构建与验证

运行某个配置的构建:

et build -c host_debug

et默认会为本地开发选择合适的构建(源码中_defaultHostDebug()的默认值是host_debug,见 build_plan.dart)。RBE 工作正常时,日志中应出现类似输出:

[2024-04-22T09:58:48.643][windows/host_debug: GN]: OK [2024-04-22T09:58:59.361][windows/host_debug: RBE startup]: OK

两行分别代表 GN 配置阶段与 RBE proxy 启动阶段成功。这也是判断 RBE 是否真正接通的第一个检查点。

禁用 RBE:--no-rbe

如果希望本次构建走本地,给build命令加--no-rbe标志:

et build -c host_debug --no-rbe

源码层面,RBE 开关的处理逻辑在 build_plan.dart:当--rbe被显式开启但环境中不存在 RBE 配置(即engine/src/flutter/build/rbe目录缺失)时,会直接抛出FatalError("RBE requested but configuration not found"),并附带引导说明。同时,--rbe与--lto、--no-rbe、--no-lto属于保留 GN 参数(reservedGnArgs),不能通过--gn-args传入,否则会触发reservedGnArgsError提示改用et的直接参数(见 build_plan.dart)。

控制 LTO:--lto

LTO(链接时代码优化)在本地构建中既慢又少有用武之地,因此et在所有构建中默认关闭 LTO——即使某个构建配置里显式指定了 LTO 也会被覆盖。需要时显式传入:

et build -c host_debug --lto

源码中这一默认逻辑位于 build_plan.dart:若用户未显式解析--lto,则默认取!build.gn.contains('--no-lto')的反值,最终在toGnArgs()中生成--lto或--no-lto传给 GN(见 build_plan.dart)。

自定义构建:编辑构建配置 JSON

除开关 RBE 与 LTO 外,build命令目前不支持在命令行层面自定义构建参数。如果需要自定义 GN 标志或 Ninja 目标,官方做法是本地修改构建配置 JSON 文件,尤其是专为本地引擎开发准备的//flutter/ci/builders/local_engine.json。

在 flutter_flutter 仓库中,engine/src/flutter/ci/builders/local_engine.json 收录了大量常用本地构建。以其中的macos/host_debug为例,其结构为:

{ "cas_archive": false, "drone_dimensions": [ "os=Mac-14|Mac-15", "device_type=none" ], "gclient_variables": { "download_android_deps": false, "download_jdk": false, "use_rbe": true }, "gn": [ "--runtime-mode", "debug", "--no-stripped", "--no-lto", "--xcode-symlinks", "--rbe", "--no-goma" ], "name": "macos/host_debug", "description": "Builds a debug mode engine for a macOS host.", "ninja": { "config": "host_debug", "targets": [] }, "properties": { "$flutter/osx_sdk": { "sdk_version": "16c5032a" } } }

各字段的作用(完整规范见 engine/src/flutter/ci/builders/README.md 中的 Build Definition Language 说明):

  • name:构建名,et build -c <name>中的<name>即取自此处;命名约定为<平台>/<配置>,et会按当前平台对名称做"mangling"处理(见 build_utils.dart,如macos/host_debug在 macOS 上简化为host_debug)。
  • drone_dimensions:选择执行该子构建的 CI bot(os、device_type等),本地运行时用于表达目标平台属性。
  • gclient_variables:传给gclient sync的变量,如use_rbe: true、download_android_deps: false。
  • gn:传给tools/gn脚本的 GN 参数列表,如--rbe、--no-goma、--no-lto、--runtime-mode debug。仓库中 DEPS 的reclient_version与这里配合,决定了实际拉取的 reclient 工具链版本。
  • ninja.config:GN 生成的输出目录名(对应out/<config>)。
  • ninja.targets:额外指定要构建的 Ninja 目标,为空数组表示构建该配置的全部默认目标。
  • properties.$flutter/osx_sdk.sdk_version:macOS 构建使用的 Xcode "Build version" 值。这一点与后文"构建缓慢"排错一节直接相关——本地 macOS 开发者应使用与 CI bot 相同的 Xcode 版本。

何时不应放入local_engine.json:如果一个构建的产出物要用于 CI 归档或测试,就不应放入local_engine.json,而应放入与其用途匹配的专用 JSON 文件(如 linux_host_engine.json、windows_host_engine.json 等)。反之,若某个本地常用配置在local_engine.json中缺失、且会被多人长期使用,官方建议将该配置检入仓库并让其跑在 CI 上——这能让 RBE 远端缓存保持"温暖"(warm),从而显著加速本地构建。仓库中 30 余个ci/builders/*.json文件正是这一机制的产物。

et工具的底层构建流程

把以上命令行行为串起来看,et build的实际执行路径是:

  1. build_command.dart 读取BuildPlan(含useRbe、useLto、并发数、额外 GN 参数);
  2. build_utils.dart 的runBuild()组装 GN 参数(RBE 关闭时追加--no-rbe),构造BuildRunner并传入RbeConfig;
  3. BuildRunner依次执行 GN 配置、启动 RBE proxy(bootstrap)、运行 ninja、关闭 proxy,整个生命周期由et统一托管——这正是官方文档强调"所有 RBE 构建必须经由et"的实现根基。

保持与 RBE 的兼容性:rebase_path()的相对路径约束

RBE 对编译命令中的路径非常敏感。官方文档给出两条硬性约束:

  1. 编译命令中的所有路径必须是相对路径;
  2. 这些相对路径必须全部解析到引擎源码树(engine source tree)内部的文件。

落到 GN 层面,这意味着:只有确定结果不会用于编译或链接命令时,rebase_path()才可以省略第二个参数(即基准路径参数)。仓库树中确实存在大量省略第二参数的rebase_path()用法,但安全的经验法则是:不要新增单参数形式的rebase_path()。

在 flutter_flutter 仓库中可以看到规范用法示例,例如 engine/src/flutter/BUILD.gn 中的rebase_path(inputs[0], root_build_dir)明确传入root_build_dir作为基准,确保产物路径相对构建目录输出,从而满足 RBE 对相对路径的要求;engine/src/flutter/build/archives/BUILD.gn 同样传入了$root_build_dir基准。为 RBE 新增 GN 规则或修改编译参数时,请始终遵循这一模式。

故障排查

错误:获取凭据失败(Error obtaining credentials)

运行et build时若出现如下错误:

E0815 09:30:03.169505 1413247 main.go:147] Error obtaining credentials: application default credentials were invalid: could not get valid Application Default Credentials token: oauth2: cannot fetch token: 400 Bad Request

检查~/.config/gcloud/application_default_credentials.json,确认你是否登录了错误的项目或账号(例如同时登录了多个账号导致默认凭据混乱)。修复方式为重置默认凭据:

gcloud auth application-default login

构建缓慢(Slow builds)

RBE 构建变慢通常有几个原因,按常见程度排序:

  1. 远端缓存是冷的(cold):缓存温暖时,一次编译步骤仅需从缓存下载已编译的翻译单元(compiled TU);缓存冷时,远端 worker 必须真实执行编译命令,耗时自然更长。
  2. worker pool 过载:过载时部分编译命令会回退到本地执行,同样更慢。
  3. 网络带宽受限:带宽不足时 RBE 会吞吐受限(文档作者曾观察到在家中因 RBE 占满低配 Comcast Business 连接而导致构建缓慢)。

此外还有两个平台相关的针对性建议:

  • macOS 开发者:确保本机 Xcode 版本与 CI bot 一致。用xcodebuild -version查看 "Build version" 值,应与 local_engine.json 中所运行构建的sdk_version(例如16c5032a)匹配。
  • Google corp macOS 设备:各类后台与监控进程可能拖慢构建(RBE 与非 RBE 皆然),可按文档指引关闭部分此类进程;同时应按照相关说明将引擎源码目录加入 Spotlight 隐私列表,关闭 Spotlight 对源码目录的扫描。

临时降级为本地构建的快捷方式:当 RBE 变慢时,非 RBE 构建(尤其是增量构建)往往更快。你可以在不失效现有构建产物的情况下,通过环境变量禁用远端执行:

RBE_exec_strategy=local

Proxy 状态与调试日志

⚠️警告:由于et会在执行构建时启动与停止本地 RBE proxy,以下命令仅在构建运行期间有效。

查询本地 RBE proxy 的状态:

buildtools/mac-arm64/reclient/reproxystatus

该命令会输出已完成的 action 数、进行中的 action 数,以及远端执行、本地执行、远端缓存命中三项统计。示例输出:

$ reproxystatus Reproxy(unix:///tmp/reproxy.sock) is OK Actions completed: 4405 (750 cache hits, 3075 racing locals, 580 racing remotes) Actions in progress: 11 QPS: 12

解读:

  • cache hits:远端缓存命中数,缓存命中越多构建越快;
  • racing locals/racing remotes:RBE 的 racing 模式下本地与远端执行的 action 数(racer 会同时启动本地与远端执行、取先完成者);
  • QPS:每秒处理的 action 数。

RBE 日志位于系统/tmp目录:/tmp/reproxy.{INFO,WARNING,ERROR}与/tmp/bootstrap.{INFO,WARNING,ERROR}。这些日志文件是排查 RBE 问题的一手资料。

CI 运行中,RBE 日志还可以通过构建页面中teardown remote execution > collect rbe logs步骤下的链接获取:

依赖分析失败(Dependency analysis failures)

上述日志对排查 RBE 的依赖分析(dependency analysis)失败很有价值。依赖分析失败的原因多种多样,但本地开发中常见的一种是源文件本身存在某种格式错误(malformed)。排查手段很简单:关闭 RBE 做一次本地构建,即可确认问题是否与 RBE 的依赖分析相关。

参考资料与延伸阅读

关于 RBE 工具链的进一步信息,可结合 flutter_flutter 仓库内的以下资源继续深入:

  • RBE 工具链本体(reproxy、rewrapper、bootstrap 等)属于 reclient 项目;这些工具文档稀缺,其命令行参数以源码为准。本地对应的工具二进制由 DEPS 中reclient_version(infra/rbe/client/${{platform}})与flutter_internal/rbe/reclient_cfgs两个 CIPD 依赖决定,并在gclient sync时下载到 engine/src/flutter/buildtools 与engine/src/flutter/build/rbe目录。
  • RBE 版本管理:本地开发使用的 RBE 版本在根目录 DEPS 中声明,需要不定期手动滚动升级;CI 使用的版本在 LUCI recipe 中配置,同样需要手动滚动。两者升级节奏与 clang 升级相互关联。
  • 构建配置体系:engine/src/flutter/ci/builders/README.md 完整介绍了 Build Definition Language(builds、tests、generators、archives 的 JSON 结构),是理解local_engine.json及全部 CI 构建配置的权威文档。
  • et工具源码:engine/src/flutter/tools/engine_tool/lib/src/build_plan.dart、build_utils.dart、environment.dart 分别实现了构建计划解析、构建执行与 RBE 环境探测,可作为扩展et行为时的阅读起点。
  • 仓库构建配置全集:engine/src/flutter/ci/builders 目录下的 30 余个 JSON 文件分别覆盖 Linux/macOS/Windows 主机的 Android、iOS、host、web(wasm)等引擎构建变体,其中--no-rbe的 web 构建(如linux/wasm_release)展示了同一套配置体系下关闭 RBE 的写法。

如果你同时关注 flutter_flutter 的 OpenHarmony 适配侧构建流程,engine/scripts/ohos.gclient 提供了本仓库 OpenHarmony 版本的 gclient 模板(deps_file指向DEPS_ohos),其中custom_vars的结构与本文第一节完全一致,可作为对照参考。

  • 跨平台
  • 前端
  • 移动开发
  • OpenHarmony

【免费下载链接】flutter_flutter

本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。

项目地址:https://gitcode.com/CPF-Flutter/flutter_flutter
点击查看免费下载

相关推荐

上一篇:MCA Selector终极指南:5个简单步骤彻底解决Minecraft世界卡顿问题
下一篇:如何构建个人游戏云服务器:Sunshine自托管串流平台完整配置指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 2:52:57

基于炬芯ATS308X的Find my防丢器查找器功能实现

# ATS3089P 设备查找与防丢报警本功能用于手机 BLE App 查找附近开发板&#xff0c;以及 BLE 连接丢失后的本机声音报警。PC 直接使用原有普通 UART 串口发送指令。这里的“Find My”是本地 BLE 查找功能&#xff0c;没有接入 Apple 查找网络。查找声音由固件实时合成&#xff…

作者头像 李华
网站建设 2026/10/15 2:51:09

BiliPai 的 Miuix 导航深度集成:从源码捆绑到预测式返回策略定制

移动开发音视频插件系统 【免费下载链接】BiliPai 原生、纯净、可扩展 —— 重新定义你的 B 站体验 项目地址&#xff1a; https://gitcode.com/gh_mirrors/bil/BiliPai 点击查看 免费下载 导读 本文围绕 BiliPai 项目中捆绑的 miuix-navigation 模块展开&#xff0c;系统讲解…

作者头像 李华
网站建设 2026/10/15 2:44:39

Flutter 图文混排实战:商品列表布局与滚动性能优化

1. 从一张商品卡片说起&#xff1a;图文混排到底难在哪做移动端电商项目的人&#xff0c;迟早都会撞上「商品列表图文混排」这堵墙。表面上看&#xff0c;无非就是左边一张图、右边几行字&#xff0c;或者上面一张大图、下面标题价格&#xff0c;用Row和Column拼一拼就完事了。…

作者头像 李华
网站建设 2026/10/15 2:43:28

基于Springboot社区医院管理系统【附源码+文档】

&#x1f495;&#x1f495;作者&#xff1a; 米罗学长 &#x1f495;&#x1f495;个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 &#x1f495;&#x1f495;各类成品Java[毕][设] 。ssm&#xff0c;springboot&#xff0c;vue等项目&#…

作者头像 李华