淘先锋技术网

首页 1 2 3 4 5 6 7


前言

对前文Dart - dill文件序列化为可读文本做一些补充。

开发环境

  • macOS: 13.4
  • Dart: 3.0.5
  • Flutter: 3.10.5

app.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项目根目录路径下执行运行命令:

-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

screenshot1

  • --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.<anonymous closure> (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.<anonymous closure> (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文件(右侧)有所差异,不过差别不大:

screenshot2

DEPS文件

前文中提到了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文件。

最后

如果这篇文章对你有所帮助,请不要吝啬你的点赞👍加星🌟,谢谢~