Flutter 引擎编译实战:从 GN 参数解析到各平台构建全流程(基于 Flutter 官方引擎文档)
本篇以 Flutter 仓库官方文档 Compiling-the-engine.md 为主体,系统讲解如何为 Android、iOS、桌面(macOS/Linux/Windows)、Fuchsia 和 Web 目标编译 Flutter 引擎。读完本文,你将掌握 gn + ninja 两阶段构建模型的每个关键参数(--unoptimized、--runtime-mode、--no-lto、--mac-cpu 等)的确切含义,能够独立完成一次完整的引擎构建,并用 flutter 工具以本地引擎运行应用、定位常见编译错误。
前置条件:先配好引擎开发环境
编译引擎前必须先完成环境搭建,官方文档明确要求参见 Setting-up-the-Engine-development-environment.md。核心要点回顾:
- 引擎源码自 2024 年末起位于主仓库的
engine/目录下,依赖由gclient管理; - 将 engine/scripts 下的
.gclient模板(外部开发者用standard.gclient)复制到仓库根目录作为.gclient,再执行gclient sync; - 把 engine/src/flutter/bin(内含引擎工具
et)加入PATH; - 无需单独安装 Dart SDK 与 Android SDK,
gclient sync会一并拉取。
另外,官方在 Compiling-the-engine.md 的"General Compilation Tips"中特别建议:优先使用 et(engine tool)而非手动执行 gn/ninja,它位于 engine/src/flutter/tools/engine_tool,提供 et build、et run、et test 等统一子命令,屏蔽了输出目录命名的细节。本文以文档中的手动 gn/ninja 流程为主线讲解原理,et 可作为日常替代。
编译前的通用要点与引擎更新流程
五条通用编译建议(原文完整继承)
- 本地开发调试优先用
--unopt(即--unoptimized)构建:这类构建启用额外的日志与断言检查,编译/链接标志也更利于快速编译和调试符号。反过来,做性能测试时不要使用--unoptimized。这一点在 gn 脚本 中有对应实现:args.unoptimized会直接映射为 GN 参数is_debug(gn_args['is_debug'] = args.unoptimized),并顺带关闭 LTO——源码注释写明"There is no point in enabling LTO in unoptimized builds"。 - 优化构建默认执行 LTO(链接时优化):LTO 会显著拉长链接时间并消耗大量内存。需要优化产物但想跳过 LTO 时,加
--no-lto参数。gn 脚本 中--no-lto通过dest='lto'反向控制enable_lto,并且仅在非 Windows 工具链下设置该 GN 参数("The GN arg is not available in the windows toolchain")。 - Android/iOS 需要 host 与 target 双份构建:升级 Dart SDK(例如
gclient sync追平 master)后,必须重编 host 构建,因为 host 产物需要与 Android/iOS 产物保持版本匹配。 - Web、桌面、Fuchsia 只有一个构建目标(
host或fuchsia),不存在双份构建问题。 - 备份脚本务必排除
out目录:里面会生成大量二进制产物;engine/src/flutter之外的大部分目录同理。
更新引擎代码
编译前应确保引擎代码与最新 master 同步:
git fetch upstream master
git rebase upstream/master
gclient sync -D
使用自定义 Dart SDK
面向 host/桌面时,CI 使用的是 Dart 团队提供的预构建 SDK。若要用 gclient sync 下载下来的 Dart 源码现场构建 SDK,在编辑这些源码文件后,给 //flutter/tools/gn 传 --no-prebuilt-dart-sdk。gn 脚本 中对应参数定义为 dest='prebuilt_dart_sdk' 的 action='store_false';且若设置了 --full-dart-sdk 之外的场景下缺少 Dart SDK,脚本会提示通过该 flag 从源码构建。
为 Android 编译(在 macOS 或 Linux 上)
以下步骤构建的是 flutter run 在 Android 设备上使用的引擎。所有命令都在本地 checkout 的 engine/src 目录下执行。
完整操作序列
| 命令 | 目标 |
|---|---|
./flutter/tools/gn --android --unoptimized |
设备端可执行文件(默认 arm) |
./flutter/tools/gn --android --android-cpu arm64 --unoptimized |
较新的 64 位 Android 设备 |
./flutter/tools/gn --android --android-cpu x86 --unoptimized |
x86 模拟器 |
./flutter/tools/gn --android --android-cpu x64 --unoptimized |
x64 模拟器 |
./flutter/tools/gn --unoptimized |
host 端可执行文件(编译代码所必需) |
在 Apple Silicon(M 系列芯片)上,host 构建应追加 --mac-cpu arm64 以避开 Rosetta 模拟,输出目录变为 host_debug_unopt_arm64。从源码看,--mac-cpu 的可选值正是 x64/arm64(默认 x64),而 --android-cpu 在 gn 脚本 中支持 arm、x64、x86、arm64、riscv64(默认 arm)。
3. 用 ninja 构建:
ninja -C out/android_debug_unopt # 设备端
ninja -C out/android_debug_unopt_arm64 # 64 位设备
ninja -C out/android_debug_unopt_x86 # x86 模拟器
ninja -C out/android_debug_unopt_x64 # x64 模拟器
ninja -C out/host_debug_unopt # host 端
这些命令可以组合,例如 ninja -C out/android_debug_unopt && ninja -C out/host_debug_unopt。macOS 上编译 android_debug_unopt 与 android_debug_unopt_x86 需要较旧版本的 Xcode(9.4 及以下);若只关心 x64 可忽略此限制。
构建产物是启用调试(unoptimized)且 Dart 运行在 checked 模式(debug)的二进制;其他运行模式参见 Flutter's-modes.md。
调试与版本配对规则
- 若要在引擎中调试崩溃,需要在测试应用的
android/AndroidManifest.xml的<application>元素中加android:debuggable="true"。 - 使用本地引擎配合
flutter工具的方法见 docs/tool/README.md("Using a locally built engine with the flutter tool" 一节)。通常在真机上用android_debug_unopt调试、在模拟器上用android_debug_unopt_x64。修改引擎中的 Dart 源码时,需要在应用的pubspec.yaml中加入dependency_override段(同上文档)。 - host 与 target 构建必须成对存在:用了
android_debug_unopt就必须同时构建host_debug_unopt,android_profile配host_profile,依此类推。对于android_debug_unopt_x86这类 CPU 后缀构建,无法直接构建同名的host_debug_unopt_x86(该配置不受支持),正确做法是构建host_debug_unopt后建一个指向它的符号链接host_debug_unopt_x86。工具链侧的校验逻辑可在 packages/flutter_tools/lib/src/runner/local_engine.dart 中见到(--local-engine与--local-web-sdk必须二选一指定)。
Linux 上"一次编全"脚本
如果你在 Linux 开发、在 Android 测试,且 .gclient 位于 ~/dev/flutter/engine/.gclient,官方给出如下一键脚本,会更新所有关键构建:
set -ex
cd ~/dev/flutter
git fetch upstream master
git rebase upstream/master
cd engine
gclient sync -D
cd src
flutter/tools/gn --unoptimized --runtime-mode=debug
flutter/tools/gn --android --unoptimized --runtime-mode=debug
flutter/tools/gn --android --runtime-mode=profile
flutter/tools/gn --android --runtime-mode=release
cd out
find . -mindepth 1 -maxdepth 1 -type d | xargs -n 1 sh -c 'ninja -C $0 || exit 255'
注意 --runtime-mode 的取值范围在 gn 脚本 中为 debug(默认)、profile、release、jit_release。对 --runtime-mode=profile 构建,官方还建议给 gn 追加 --no-lto:链接会快很多,仅以极小的产物体积/内存换代价(调试与性能基准场景下通常无碍)。
为 iOS 编译(在 macOS 上)
这些步骤构建 flutter run 在 iOS 设备上使用的引擎,从 engine/src 目录开始:
-
确认引擎代码最新。
-
准备设备端构建文件:
./flutter/tools/gn --ios --unoptimized # 真机 ./flutter/tools/gn --ios --simulator --unoptimized # 模拟器- 该步骤同时会在
out/ios_debug_unopt/flutter_engine.xcodeproj生成 Xcode 工程,便于直接打开操作引擎源码; - 各构建模式与 flag 的讨论见 Flutter's-modes.md;
- arm64 Mac 上的模拟器可加
--simulator-cpu=arm64,输出到out/ios_debug_sim_unopt_arm64(--simulator-cpu可选x64/arm64,默认x64;且--simulator仅限 iOS 目标,gn 脚本 中会显式校验并报错)。
- 该步骤同时会在
-
准备 host 端构建文件:
./flutter/tools/gn --unoptimized(Apple Silicon 加--mac-cpu arm64,生成host_debug_unopt_arm64)。 -
构建全部产物:
ninja -C out/ios_debug_unopt && ninja -C out/host_debug_unopt模拟器用
out/ios_debug_sim_unopt。
通常在真机上用 ios_debug_unopt 调试、在模拟器上用 ios_debug_sim_unopt。修改引擎 Dart 源码同样需要 pubspec.yaml 中的 dependency_override(见 docs/tool/README.md)。在 Xcode 中调试 iOS 引擎构建的方法另见 Debugging-the-engine.md 的 "Debugging iOS builds with Xcode" 一节。
为 macOS 或 Linux 编译(桌面嵌入层)
这些步骤构建桌面嵌入层(desktop embedding)以及 flutter test 在宿主工作站上使用的引擎:
- 确认引擎代码最新。
- macOS 上安装 Metal 构建工具:
xcodebuild -downloadComponent MetalToolchain。 ./flutter/tools/gn --unoptimized准备构建文件:--unoptimized会禁用 C++ 编译器优化。二进制去符号(strip)行为因平台而异:macOS 上直接输出未 strip 的二进制;Linux 上未 strip 的二进制会放到构建目录下的exe.unstripped子目录;- Apple Silicon 使用
./flutter/tools/gn --unoptimized --mac-cpu=arm64。
ninja -C out/host_debug_unopt构建桌面未优化二进制:- 若未使用
--unoptimized,则改用ninja -C out/host_debug; - Apple Silicon 使用
ninja -C out/host_debug_unopt_arm64。
- 若未使用
本配置通常使用 host_debug_unopt 构建。此外,若系统安装了 ccache,可在第 3 步的 gn 上加 --ccache 开启编译缓存(gn 脚本 中会将其映射为 use_ccache = True),在切换分支等场景下可显著加速后续构建。
为 Windows 编译
警告:Windows 上只能构建部分二进制(主要是
gen_snapshot与桌面嵌入层)。
另外确保引擎 checkout 目录不要嵌套过深,避免构建脚本处理超长路径出错。
-
安装 Visual Studio(非 Google 员工),并必须安装 Debugging Tools for Windows 10。
-
确认引擎代码最新。
-
启用长路径支持:以管理员身份打开 PowerShell 执行:
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -Force -
非 Google 员工需设置以下环境变量,把 depot_tools 指向本地 Visual Studio:
DEPOT_TOOLS_WIN_TOOLCHAIN=0 GYP_MSVS_OVERRIDE_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community" # 改为你的 VS 安装位置 WINDOWSSDKDIR="C:\Program Files (x86)\Windows Kits\10" # 改为你的 Windows Kits 位置同时确保
Python27在PATH中位于其他 python 之前。 -
切换到
engine/src/目录。 -
准备构建文件:
python .\flutter\tools\gn --unoptimized。- 若只构建
gen_snapshot:python .\flutter\tools\gn [--unoptimized] --runtime-mode=[debug|profile|release] [--android]。
- 若只构建
-
构建:
ninja -C .\out\<上一步生成的目录>。- 若使用了非 debug 配置,使用
ninja -C .\out\<目录> gen_snapshot。桌面 shell 尚不支持 release 与 profile 配置。
- 若使用了非 debug 配置,使用
为 Fuchsia 编译
配置 gclient 并同步依赖
-
Fuchsia 构建仅支持 Linux。需要在
engine/.gclient(若当前目录是engine/src则为../.gclient)中加入custom_vars:solutions = [ { # ... "custom_vars": { "download_fuchsia_deps": True, "run_fuchsia_emu": True, }, }, ]若不在本地跑测试,可忽略
"run_fuchsia_emu": True。然后执行gclient sync -D。警告:本地跑测试需要启用 KVM(或在 GCP 虚拟机上启用嵌套虚拟化)。Fuchsia 与测试都会运行在 QEMU 上。
-
准备并构建:
./flutter/tools/gn --fuchsia --no-lto- 默认生成
out/fuchsia_debug_x64(--fuchsia-cpu可选x64/arm64,默认x64); - 用
--fuchsia-cpu arm64构建 arm64 组件,输出目录为out/fuchsia_debug_arm64; - 用
--runtime-mode=release或--runtime-mode=profile选择其他模式,与其他平台一致; - 去掉
--no-lto即启用链接时优化。
ninja -C out/fuchsia_debug_x64 -k 0-
-k 0表示构建全部目标但忽略已知错误;也可以显式指定目标以省去-k 0:flutter/shell/platform/fuchsia:fuchsia \ flutter/shell/platform/fuchsia/dart_runner:dart_runner_tests \ fuchsia_tests -
如有
autoninja可用则优先使用; -
release 构建用
-C out/fuchsia_release_x64,其余配置同理,只是out/下目录名不同。
- 默认生成
-
本地运行全部测试(with_envs.py 包装 flutter/testing/fuchsia/run_tests.py):
python3 flutter/tools/fuchsia/with_envs.py flutter/testing/fuchsia/run_tests.py-
默认运行
out/fuchsia_debug_x64中的测试,按配置不同可能耗时 5 分钟左右,gtest 输出直接打到终端; -
测试 release 构建则在命令末尾追加
fuchsia_release_x64:python3 flutter/tools/fuchsia/with_envs.py flutter/testing/fuchsia/run_tests.py fuchsia_release_x64
-
为 Web 编译
构建 Web 引擎使用 felt 工具("Flutter Engine Local Tester"),其文档见 engine/src/flutter/lib/web_ui/README.md。felt 位于 engine/src/flutter/lib/web_ui/dev 目录,建议将该目录加入 PATH。
要使用本地构建的 Web 引擎测试 Flutter,给 flutter 命令追加 --local-web-sdk=wasm_release:
flutter run --local-web-sdk=wasm_release -d chrome
flutter test --local-web-sdk=wasm_release test/path/to/your_test.dart
从源码看,local-web-sdk 是 flutter 工具的全局选项,定义在 flutter_command_runner.dart(kLocalWebSDKOption = 'local-web-sdk'),并由 local_engine.dart 解析,工具还会根据该值反查引擎源码位置——这与 Android/iOS 的 --local-engine 是并行的两条本地引擎接入路径。
在 Windows 上编译 Web 引擎
Windows 上可能需要额外步骤,使用 cmd.exe 并以管理员身份运行:
- 确保安装 Visual Studio,并设置:
GYP_MSVS_OVERRIDE_PATH = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community"(改为你安装的版本路径)GYP_MSVS_VERSION = 2017
- 确保 depot_tools、ninja、python 已安装并加入
PATH,并设置 depot_tools 变量DEPOT_TOOLS_WIN_TOOLCHAIN = 0。若出现 python 相关报错,可尝试改用 Python 2。 - 确保引擎代码最新。若该步骤出现 git 认证错误,可改用 Git Bash。
python .\flutter\tools\gn --unoptimized --full-dart-sdk准备构建文件。ninja -C .\out\<上一步生成的目录>构建。
测试与调试同前(--local-web-sdk=wasm_release),跑引擎测试时使用 felt_windows.bat:
felt_windows.bat test
为测试编译
Dart 测试
运行 Dart 测试前,先构建引擎:
flutter/tools/gn --unoptimized
ninja -C out/host_debug_unopt/
然后:
-
native 侧执行
run_tests(engine/src/flutter/testing/run_tests.py 支持--type等参数筛选测试类型):python3 flutter/testing/run_tests.py --type dart -
Web 侧使用
felt:cd flutter/lib/web_ui dev/felt test [test file]
排错:Version Solving Failed
随着 Dart 版本迭代,你偶尔会遇到依赖解析错误,例如:
The current Dart SDK version is 2.7.0-dev.0.0.flutter-1ef444139c.
Because ui depends on <a pub package> 1.0.0 which requires SDK version >=2.7.0 <3.0.0, version solving failed.
原因通常是 gclient sync 不会更新 git tags。两种解法:
- 在
engine/src/third_party/dart下执行git fetch --tags origin; - 或者带 tags 参数重新同步:
gclient sync --with_tags。
延伸阅读
- Setting-up-the-Engine-development-environment.md:gclient bootstrap、
et加入 PATH、编辑器(VSCode/clangd、Xcode、Android Studio)集成配置。 - Debugging-the-engine.md:用本地引擎运行 Flutter 应用、各平台调试引擎的具体方法。
- Flutter's-modes.md:debug/profile/release 等运行模式与构建目录命名(如
android_debug_unopt)的完整对应关系。 - docs/tool/README.md:
--local-engine与pubspec.yaml中dependency_override的用法。 - engine/src/flutter/tools/engine_tool:
et工具文档,推荐将其作为日常构建入口。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00