对前文Dart - dill文件序列化为可读文本做一些补充。
因为Flutter项目编译后会自动生成app.dill
文件(位于项目根目录下的.dart_tool/flutter_build/xxx/app.dill
路径),同时自动生成的app.dill
文件能正常序列化为文本,所以不手动生成是没问题的。如果非要按照以下命令手动生成app.dill
文件:
dart compile kernel lib/main.dart --output lib/app.dill
一般会报这样的错:
/xxx/flutter/packages/flutter/lib/src/material/animated_icons.dart:9:8: Error: Dart library 'dart:ui' is not available on this platform.
import 'dart:ui' as ui show Canvas, Paint, Path;
^
Context: The unavailable library 'dart:ui' is imported through these packages:
package:untitled => package:flutter => dart:ui
...
Detailed import paths for (some of) the these imports:
package:untitled/main.dart => package:flutter/material.dart => package:flutter/src/material/about.dart => package:flutter/foundation.dart => package:flutter/src/foundation/assertions.dart => package:flutter/src/foundation/diagnostics.dart => package:flutter/src/foundation/debug.dart => dart:ui
...
从报错信息看,似乎是因为使用了Flutter相关的库导致的。执行dart compile kernel -h
命令看输出结果也没几个参数可以设置,难道Flutter编译项目时用的是其他命令?
在Flutter项目根目录路径下执行运行命令:
flutter run -v
-v
参数的作用是打印执行命令过程中的日志。虽然日志很长,但是可以用app.dill
为关键词搜索找到关键日志:
[ +1 ms] /xxx/flutter/bin/cache/dart-sdk/bin/dart --disable-dart-dev
/xxx/flutter/bin/cache/dart-sdk/bin/snapshots/frontend_server.dart.snapshot --sdk-root
/xxx/flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk/ --incremental --target=flutter --experimental-emit-debug-metadata
-DFLUTTER_WEB_AUTO_DETECT=true -DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/45f6e009110df4f34ec2cf99f63cf73b71b7a420/ --output-dill
/var/folders/_p/n8w3bslx2qg8sh057tm1hcmw0000gn/T/flutter_tools.pCnbY1/flutter_tool.BWP10J/app.dill --packages /xxx/untitled/.dart_tool/package_config.json
-Ddart.vm.profile=false -Ddart.vm.product=false --enable-asserts --track-widget-creation --filesystem-scheme org-dartlang-root --initialize-from-dill
build/4d25a1cda3833f76c80232d3b1a3704b.cache.dill.track.dill --verbosity=error --enable-experiment=alternative-invalidation-strategy
咦?竟然用的是frontend_server.dart.snapshot
,这是Dart前端编译的快照文件。相比于dart compile kernel
命令,可设置的参数就丰富多了。实测必须要指定的关键参数有两个,分别是--sdk-root
和--target
:
--sdk-root
指定SDK根路径,如果不设置会报一堆关于找不到库的错误,虽然最后能生成dill
文件,但是序列化为文本后会出现很多Problems in library
:
--target
参数用于确定可用核心库的目标模型,默认是vm
,必须设置为flutter
。如果不设置会报这样的错:
Unhandled exception:
Null check operator used on a null value
#0 DillLoader.read (package:front_end/src/fasta/dill/dill_loader.dart:123:38)
#1 DillTarget.loadExtraRequiredLibraries (package:front_end/src/fasta/dill/dill_target.dart:60:14)
#2 DillLoader.read (package:front_end/src/fasta/dill/dill_loader.dart:138:16)
#3 DillLoader.appendLibraries (package:front_end/src/fasta/dill/dill_loader.dart:290:18)
#4 generateKernelInternal. (package:front_end/src/kernel_generator_impl.dart:84:27)
<asynchronous suspension>
#5 withCrashReporting (package:front_end/src/fasta/crash.dart:136:12)
<asynchronous suspension>
#6 kernelForProgramInternal. (package:front_end/src/api_prototype/kernel_generator.dart:62:29)
<asynchronous suspension>
#7 kernelForProgramInternal (package:front_end/src/api_prototype/kernel_generator.dart:61:10)
<asynchronous suspension>
#8 kernelForProgram (package:front_end/src/api_prototype/kernel_generator.dart:50:11)
<asynchronous suspension>
#9 compileToKernel (package:vm/kernel_front_end.dart:452:22)
<asynchronous suspension>
#10 FrontendCompiler.compile (package:frontend_server/frontend_server.dart:620:17)
<asynchronous suspension>
#11 starter (package:frontend_server/starter.dart:99:12)
<asynchronous suspension>
#12 main (file:///opt/s/w/ir/x/w/sdk/pkg/frontend_server/bin/frontend_server_starter.dart:13:14)
<asynchronous suspension>
最终得到的可用命令:
dart /xxx/flutter/bin/cache/dart-sdk/bin/snapshots/frontend_server.dart.snapshot --sdk-root /xxx/flutter/bin/cache/artifacts/engine/common/flutter_patched_sdk/ --target=flutter xxx.dart --output-dill xxx.dill
请根据实际需要替换命令中的Flutter SDK等路径。由于参数有所精简,所以用以上命令生成的app.dill
文件(左侧)和Flutter编译自动生成的app.dill
文件(右侧)有所差异,不过差别不大:
前文中提到了DEPS
文件,和pubspec.yaml
文件相比,除了指定了项目的依赖项,还配置了hook
用于在.dart_tool
目录下生成package_config.json
文件,而pubspec.yaml
文件只是配置文件,package_config.json
文件的生成需要借助dart pub get
命令。
打开Dart SDK目录下的sdk/DEPS
文件,脚本拉到最后面就是hook
数组:
hooks = [
{
# Generate the .dart_tool/package_confg.json file.
'name': 'Generate .dart_tool/package_confg.json',
'pattern': '.',
'action': ['python3', 'sdk/tools/generate_package_config.py'],
},
...
]
当用于同步依赖项的gclient sync
命令执行结束后会执行这些hook
。首个hook
就是用于生成package_confg.json
文件,执行的是generate_package_config.py
脚本,最终执行到位于同目录下的generate_package_config.dart
文件。
如果这篇文章对你有所帮助,请不要吝啬你的点赞加星,谢谢~