首页
/ Flutter 引擎编译实战:从 GN 参数解析到各平台构建全流程(基于 Flutter 官方引擎文档)

Flutter 引擎编译实战:从 GN 参数解析到各平台构建全流程(基于 Flutter 官方引擎文档)

2026-09-06 16:09:12作者:苗圣禹Peter

本篇以 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 buildet runet test 等统一子命令,屏蔽了输出目录命名的细节。本文以文档中的手动 gn/ninja 流程为主线讲解原理,et 可作为日常替代。

编译前的通用要点与引擎更新流程

五条通用编译建议(原文完整继承)

  1. 本地开发调试优先用 --unopt(即 --unoptimized)构建:这类构建启用额外的日志与断言检查,编译/链接标志也更利于快速编译和调试符号。反过来,做性能测试时不要使用 --unoptimized。这一点在 gn 脚本 中有对应实现:args.unoptimized 会直接映射为 GN 参数 is_debuggn_args['is_debug'] = args.unoptimized),并顺带关闭 LTO——源码注释写明"There is no point in enabling LTO in unoptimized builds"。
  2. 优化构建默认执行 LTO(链接时优化):LTO 会显著拉长链接时间并消耗大量内存。需要优化产物但想跳过 LTO 时,加 --no-lto 参数。gn 脚本--no-lto 通过 dest='lto' 反向控制 enable_lto,并且仅在非 Windows 工具链下设置该 GN 参数("The GN arg is not available in the windows toolchain")。
  3. Android/iOS 需要 host 与 target 双份构建:升级 Dart SDK(例如 gclient sync 追平 master)后,必须重编 host 构建,因为 host 产物需要与 Android/iOS 产物保持版本匹配。
  4. Web、桌面、Fuchsia 只有一个构建目标hostfuchsia),不存在双份构建问题。
  5. 备份脚本务必排除 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-sdkgn 脚本 中对应参数定义为 dest='prebuilt_dart_sdk'action='store_false';且若设置了 --full-dart-sdk 之外的场景下缺少 Dart SDK,脚本会提示通过该 flag 从源码构建。

为 Android 编译(在 macOS 或 Linux 上)

以下步骤构建的是 flutter run 在 Android 设备上使用的引擎。所有命令都在本地 checkout 的 engine/src 目录下执行。

完整操作序列

  1. 确认引擎代码已是最新(见上文)。
  2. gn 准备构建文件:
命令 目标
./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-cpugn 脚本 中支持 armx64x86arm64riscv64(默认 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_unoptandroid_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_unoptandroid_profilehost_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(默认)、profilereleasejit_release。对 --runtime-mode=profile 构建,官方还建议给 gn 追加 --no-lto:链接会快很多,仅以极小的产物体积/内存换代价(调试与性能基准场景下通常无碍)。

为 iOS 编译(在 macOS 上)

这些步骤构建 flutter run 在 iOS 设备上使用的引擎,从 engine/src 目录开始:

  1. 确认引擎代码最新

  2. 准备设备端构建文件:

    ./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 脚本 中会显式校验并报错)。
  3. 准备 host 端构建文件:./flutter/tools/gn --unoptimized(Apple Silicon 加 --mac-cpu arm64,生成 host_debug_unopt_arm64)。

  4. 构建全部产物:

    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 在宿主工作站上使用的引擎:

  1. 确认引擎代码最新
  2. macOS 上安装 Metal 构建工具:xcodebuild -downloadComponent MetalToolchain
  3. ./flutter/tools/gn --unoptimized 准备构建文件:
    • --unoptimized 会禁用 C++ 编译器优化。二进制去符号(strip)行为因平台而异:macOS 上直接输出未 strip 的二进制;Linux 上未 strip 的二进制会放到构建目录下的 exe.unstripped 子目录
    • Apple Silicon 使用 ./flutter/tools/gn --unoptimized --mac-cpu=arm64
  4. 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 目录不要嵌套过深,避免构建脚本处理超长路径出错。

  1. 安装 Visual Studio(非 Google 员工),并必须安装 Debugging Tools for Windows 10

  2. 确认引擎代码最新

  3. 启用长路径支持:以管理员身份打开 PowerShell 执行:

    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -Force
    
  4. 非 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 位置
    

    同时确保 Python27PATH 中位于其他 python 之前。

  5. 切换到 engine/src/ 目录。

  6. 准备构建文件:python .\flutter\tools\gn --unoptimized

    • 若只构建 gen_snapshotpython .\flutter\tools\gn [--unoptimized] --runtime-mode=[debug|profile|release] [--android]
  7. 构建:ninja -C .\out\<上一步生成的目录>

    • 若使用了非 debug 配置,使用 ninja -C .\out\<目录> gen_snapshot。桌面 shell 尚不支持 release 与 profile 配置。

为 Fuchsia 编译

配置 gclient 并同步依赖

  1. 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 上。

  2. 准备并构建:

    ./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/ 下目录名不同。

  3. 本地运行全部测试(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.mdfelt 位于 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-sdkflutter 工具的全局选项,定义在 flutter_command_runner.dartkLocalWebSDKOption = 'local-web-sdk'),并由 local_engine.dart 解析,工具还会根据该值反查引擎源码位置——这与 Android/iOS 的 --local-engine 是并行的两条本地引擎接入路径。

在 Windows 上编译 Web 引擎

Windows 上可能需要额外步骤,使用 cmd.exe 并以管理员身份运行:

  1. 确保安装 Visual Studio,并设置:
    • GYP_MSVS_OVERRIDE_PATH = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community"(改为你安装的版本路径)
    • GYP_MSVS_VERSION = 2017
  2. 确保 depot_tools、ninja、python 已安装并加入 PATH,并设置 depot_tools 变量 DEPOT_TOOLS_WIN_TOOLCHAIN = 0。若出现 python 相关报错,可尝试改用 Python 2。
  3. 确保引擎代码最新。若该步骤出现 git 认证错误,可改用 Git Bash。
  4. python .\flutter\tools\gn --unoptimized --full-dart-sdk 准备构建文件。
  5. 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_testsengine/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。两种解法:

  1. engine/src/third_party/dart 下执行 git fetch --tags origin
  2. 或者带 tags 参数重新同步:gclient sync --with_tags

延伸阅读

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