概念
Flutter Engine使用GN和Ninja进行编译,GN编译后生成Ninja的构建文件,Ninja将输入文件编译成最终产物。
- depot_tools:一个工具包,包含gclient,gn和ninja等工具
- ninja:是google推出的注重速度的构建工具,将编译任务并行组织,大大提高构建速度
- gclient:代码获取工具,是google推出的用于管理多源项目所编写的脚本,可以将多个源码管理系统中的代码放在一起管理。甚至包括将git和svn代码放在一起管理。
- .gclient文件是gclient的控制文件,是一个pythone脚本,格式如下:
solutions = [
{
//checkout出源码的名字
"name" : "src",
//源码所在的目录
"url" : "svn://svnserver/component/trunk/src",
//这是一个文件名(不包括路径),指在工程目录中包含依赖列表的文件,该项为可选,默认值为"DEPS"
"deps_file" :"DEPS"
//这是一个可选的字典对象,会覆盖工程的"DEPS"文件定义的条目
"custom_deps" : {
# To use the trunk of a component instead of what's in DEPS:
#"component": "https://svnserver/component/trunk/",
# To exclude a component from your working copy:
#"data/really_large_component": None,
}
},
]
工具准备
- git
- ssh
- curl , unzip (
gclient sync
需要) - xcode
- python --version 2.7版本
- depot_tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=$PATH:/path/to/depot_tools
工程准备
- 配置ssh https://help.github.com/articles/generating-ssh-keys/
图例我加了两个key,此处只需要一个就行 - fork https://github.com/flutter/engine 到自己的git仓库
git clone <你的git上fork的engine地址>
- engine目录下vim .gclient
solutions = [
{
"managed": False,
"name": "src/flutter",
"url": "git@github.com:<your_name_here>/engine.git",
"custom_deps": {},
"deps_file": "DEPS",
"safesync_url": "",
},
]
- engine目录下
gclient sync
获取Flutter依赖的所有源代码 - 进入src/flutter目录
cd src/flutter
git remote add upstream git@github.com:flutter/engine.git
//关联到`flutter/engine`以获取master更新
git pull upstream master
版本匹配
- 找到当前flutter对应的engine版本
cat /Users/heq/flutter/bin/internal/engine.version
我这里显示的是b863200c37df4ed378042de11c4e9ff34e4e58c9
- 进入engine/src/flutter目录,将这里的flutter版本跟上一步的版本保持一致
git reset --hard b863200
当前环境查看
heq-Mac:flutter heq$ git rev-parse HEAD
b863200c37df4ed378042de11c4e9ff34e4e58c9
heq-Mac:flutter heq$ flutter --version
Flutter 1.9.1+hotfix.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 2d2a1ffec9 (3 months ago) • 2019-09-06 18:39:49 -0700
Engine • revision b863200c37
Tools • Dart 2.5.0
- 拉取数据
Checkout all the submodules at their branch DEPS revisions.
gclient sync --with_branch_heads --with_tags
编译构建
切换到engine/src目录
usage: gn [-h] [--unoptimized] [--runtime-mode {debug,profile,release}]
[--dynamic] [--interpreter] [--dart-debug]
[--target-os {android,ios,linux}] [--android]
[--android-cpu {arm,x64,x86,arm64}] [--ios] [--ios-cpu {arm,arm64}]
[--simulator] [--linux-cpu {x64,x86,arm64,arm}]
[--arm-float-abi {hard,soft,softfp}] [--goma] [--no-goma] [--lto]
[--no-lto] [--clang] [--no-clang] [--target-sysroot TARGET_SYSROOT]
[--target-toolchain TARGET_TOOLCHAIN]
[--target-triple TARGET_TRIPLE]
[--toolchain-prefix TOOLCHAIN_PREFIX]
[--operator-new-alignment OPERATOR_NEW_ALIGNMENT] [--enable-vulkan]
[--embedder-for-target] [--coverage] [--out-dir OUT_DIR]
通过GN进行的预编译生成Ninja的构建文件,除了预编译指定平台的构建文件之外,还需要预编译Host的构建文件(即PC编译平台的),当通过Ninja进行最终产物的编译时,会用到指定平台的构建文件和Host的构建文件进行编译
# unopt-debug
# prepare build files for device-side executables.
./flutter/tools/gn --unoptimized --android --runtime-mode debug --android-cpu arm
./flutter/tools/gn --unoptimized --android --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --unoptimized --android --runtime-mode debug --android-cpu x64
# prepare the build files for host-side executables.
./flutter/tools/gn --unoptimized --runtime-mode debug --android-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode debug --android-cpu x64
ninja -C out/android_debug_unopt
ninja -C out/android_debug_unopt_arm64
ninja -C out/android_debug_unopt_x64
ninja -C out/host_debug_unopt
ninja -C out/host_debug_unopt_arm64
ninja -C out/host_debug_unopt_x64
# unopt-profile
./flutter/tools/gn --unoptimized --android --runtime-mode profile --android-cpu arm
./flutter/tools/gn --unoptimized --android --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --unoptimized --android --runtime-mode profile --android-cpu x64
./flutter/tools/gn --unoptimized --runtime-mode profile --android-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode profile --android-cpu x64
ninja -C out/android_profile_unopt
ninja -C out/android_profile_unopt_arm64
ninja -C out/android_profile_unopt_x64
ninja -C out/host_profile_unopt
ninja -C out/host_profile_unopt_arm64
ninja -C out/host_profile_unopt_x64
# unopt-release
./flutter/tools/gn --unoptimized --android --runtime-mode release --android-cpu arm
./flutter/tools/gn --unoptimized --android --runtime-mode release --android-cpu arm64
./flutter/tools/gn --unoptimized --android --runtime-mode release --android-cpu x64
./flutter/tools/gn --unoptimized --runtime-mode release --android-cpu arm
./flutter/tools/gn --unoptimized --runtime-mode release --android-cpu arm64
./flutter/tools/gn --unoptimized --runtime-mode release --android-cpu x64
ninja -C out/android_release_unopt
ninja -C out/android_release_unopt_arm64
ninja -C out/android_release_unopt_x64
ninja -C out/host_release_unopt
ninja -C out/host_release_unopt_arm64
ninja -C out/host_release_unopt_x64
# opt-debug
./flutter/tools/gn --android --runtime-mode debug --android-cpu arm
./flutter/tools/gn --android --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --android --runtime-mode debug --android-cpu x64
./flutter/tools/gn --runtime-mode debug --android-cpu arm
./flutter/tools/gn --runtime-mode debug --android-cpu arm64
./flutter/tools/gn --runtime-mode debug --android-cpu x64
ninja -C out/android_debug
ninja -C out/android_debug_arm64
ninja -C out/android_debug_x64
ninja -C out/host_debug
ninja -C out/host_debug_arm64
ninja -C out/host_debug_x64
# opt-profile
./flutter/tools/gn --android --runtime-mode profile --android-cpu arm
./flutter/tools/gn --android --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --android --runtime-mode profile --android-cpu x64
./flutter/tools/gn --runtime-mode profile --android-cpu arm
./flutter/tools/gn --runtime-mode profile --android-cpu arm64
./flutter/tools/gn --runtime-mode profile --android-cpu x64
ninja -C out/android_profile
ninja -C out/android_profile_arm64
ninja -C out/android_profile_x64
ninja -C out/host_profile
ninja -C out/host_profile_arm64
ninja -C out/host_profile_x64
# opt-release
./flutter/tools/gn --android --runtime-mode release --android-cpu arm
./flutter/tools/gn --android --runtime-mode release --android-cpu arm64
./flutter/tools/gn --android --runtime-mode release --android-cpu x64
./flutter/tools/gn --runtime-mode release --android-cpu arm
./flutter/tools/gn --runtime-mode release --android-cpu arm64
./flutter/tools/gn --runtime-mode release --android-cpu x64
ninja -C out/android_release
ninja -C out/android_release_arm64
ninja -C out/android_release_x64
ninja -C out/host_release
ninja -C out/host_release_arm64
ninja -C out/host_release_x64
Tips: ninja 可使用&&,如:
ninja -C out/android_release && ninja -C out/host_release
gn操作后目录结构:
nginx操作后内容:
This builds a debug-enabled ("unoptimized") binary configured to run Dart in checked mode ("debug"). There are other versions, see Flutter's modes.
官方wiki上给出的例子
set -ex
cd ~/dev/engine/src/flutter
git fetch upstream
git rebase upstream/master
gclient sync
cd ..
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'
heq-Mac:out heq$ find . -mindepth 1 -maxdepth 1 -type d
./host_debug_unopt
./android_profile
./android_debug_unopt
./android_release
find命令: -type d 表示目录
xargs命令:可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。-n num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的。
使用方式
- flutter run --local-engine-src-path /Users/heq/engine/src --local-engine=android_debug_unopt
- 替换掉flutter目录中的engine
/Users/heq/flutter/bin/cache/artifacts/engine
使用校验
- 修改/Users/heq/engine/src/flutter/shell/platform/android/io/flutter/app/FlutterActivity.java部分代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
System.out.println("FlutterActivity.onCreate in Engine!!");
super.onCreate(savedInstanceState);
eventDelegate.onCreate(savedInstanceState);
}
- 编译engine
- 新建工程,然后使用
flutter run --local-engine-src-path /Users/heq/engine/src --local-engine=android_debug_unopt
运行,每次启动FlutterActivity,logcat打印
com.example.t_flutter_app I/System.out: FlutterActivity.onCreate in Engine!!
证明engine中的修改生效了
调试engine中的Android代码
- 导入
engine/src/flutter/shell/platform/android
作为新的工程 - 确认Engine SDK Version和Java Version
File > Project Structure > Project Settings > Project
- 可选:代码关联
File > Project Structure > Modules
消除Missing import
错误提示。主要是关联engine/src/third_party/android_support
-
在engine android工程中所需位置设上断点
- 使用
flutter run --local-engine-src-path /Users/heq/engine/src --local-engine=android_debug_unopt
运行项目工程 -
在engine android工程中attach debugger对应的项目工程,即可断点成功
参考:手把手教你编译Flutter engine
Compiling the engine
Flutter Engine与SDK的定制化与编译
Contributing to the Flutter engine
Debugging the engine