Dart是一种很好的现代编程语言,它不仅可以编译成JavaScript,还可以被AOT编译成本地独立的可执行文件。
在构建Dart SDK时,人们可以轻松选择所需的目标架构,如X64和/或ARM。尽管人们可以通过这种方式对整个SDK进行交叉编译,但不幸的是,作为SDK一部分的dart2native编译器并不支持交叉编译。为了将Dart代码编译成本地ARM二进制文件,人们必须在目标上运行编译器,这不是我们正在寻找的解决方案。
问题是,要使dart2native能够在X64主机上为Raspberry Pi交叉编译ARM二进制文件,需要做些什么?好吧,让我们先看看编译器实际做了什么。从源代码中我们可以看到,它。
- 生成一个AOT内核。
- 生成一个AOT快照,并且
- 将结果与Dart AOT运行时相结合。
GitHub上有一个很好的wiki页面,总结了Dart中不同类型的快照。它解释说,内核快照与CPU架构无关,而AOT快照可以用Dartotruntime运行。
当涉及到dart2native时,上面列出的步骤1和2只是调用外部命令,或多或少都是这样的。
<sdk>/bin/dart <sdk>/bin/snapshots/gen_kernel.dart.snapshot \
--platform <sdk>/lib/_internal/vm_platform_strong_product.dill \
--aot \
-Ddart.vm.product=true \
-o <tmp>/kernel.dill \
<source>.dart
<sdk>/bin/utils/gen_snapshot --snapshot-kind=app-aot-elf \
--elf=<tmp>/snapshot.aot \
<tmp>/kernel.dill
另一方面,第3步不是执行外部命令,而是以编程方式附加a)步骤1-2产生的快照和b)Dart AOT运行时间。作为参考,这里是一个AOT编译的Dart可执行文件的最终结构。
值得注意的是,最后一步,将最终的应用程序快照与AOT运行时合并,是可选的。它只有在编译完全独立的可执行文件时才需要。另外,人们可以直接用AOT运行时执行AOT快照,它本身就是一个可执行文件。这样,人们可以为多个Dart应用程序共享同一个AOT运行时,这可能是首选,以便在资源有限的系统中节省磁盘空间。如果你想知道这在实践中是如何运作的,请仔细看看你的Dart SDK的bin-directory. ;)
现在我们知道了dart2native在引擎盖下的作用,我们可以开始修补,看看是否可以在X64上产生ARM二进制文件。正如前面指出的,AOT内核与CPU架构无关,所以我们使用哪个Dart SDK的gen_kernel工具并不重要。让我们假设我们已经有一个为X64构建的Dart SDK。
# sdk (x64)
$ ./tools/build.py -a x64 -m product create_sdk
对于下一步,我们需要一个gen_snapshot工具,能够在X64主机架构上执行,并为ARM目标架构产生AOT快照。这并不像听起来那么复杂,因为你可以简单地为一个名为SIMARM的目标架构建立工具,以实现这一目标。
# gen_snapshot (simarm)
$ ./tools/build.py -a simarm -m product copy_gen_snapshot
注意,我们不一定需要构建整个SDK,因为我们只需要gen_snapshot工具。最后但同样重要的是,我们需要一个适用于ARM目标架构的dartaotruntime二进制文件。
# dartaotruntime (arm)
$ ./tools/build.py -a arm -m product copy_dartaotruntime
出于好奇,让我们快速检查一下目前得到的情况。
$ file out/ProductX64/dart-sdk/bin/dart2native
[...]/dart2native: Bourne-Again shell script, [...]
$ file out/ProductX64/dart-sdk/bin/dart
[...]/dart: ELF 64-bit LSB shared object, x86-64, [...]
$ file out/ProductSIMARM/dart-sdk/bin/utils/gen_snapshot
[...]/gen_snapshot: ELF 32-bit LSB executable, Intel 80386, [...]
$ file out/ProductXARM/dart-sdk/bin/dartaotruntime
[...]/dartaotruntime: ELF 32-bit LSB shared object, ARM, [...]
如你所见,dart2native实际上只是一个执行各自快照的脚本。尽管如此,看起来我们有32位的gen_snapshot,它应该能够为ARM生成AOT快照,而且我们也有一个用于ARM的dartaotruntime。 在这一点上,我们基本上掌握了所有必要的构件。我们可以手动执行gen_kernel + gen_snapshot,读取dartaotruntime,最后手工编写可执行文件,但这并不是那么简单,因为这不仅仅是附加两个文件的问题,而是需要包括正确的填充、快照偏移和一个神奇的数字。目前阻碍我们用dart2native工具做这件事的原因是,它不允许我们指定我们要使用的gen_snapshot和dartaotruntime,而是相对于dart2native查找它们。因此,我准备了一个简单的dart2native补丁,让我们可以从外部指定这两个。
用上述补丁重建dart2native后,我们准备开始测试交叉编译。为了测试,我们将使用以下一小段Dart代码,从/proc/cpuinfo读取并打印CPU模型。
import 'dart:io';
void main() {
final lines = File('/proc/cpuinfo').readAsLinesSync();
final model = lines.firstWhere((line) => line.startsWith('model name'));
print(model.split(':').last.trim());
}
结果,终于!
$ DART2NATIVE_X64=out/ProductX64/dart-sdk/bin/dart2native
$ GEN_SNAPSHOT_SIMARM=out/ProductSIMARM/dart-sdk/bin/utils/gen_snapshot
$ DARTAOTRUNTIME_XARM=out/ProductXARM/dart-sdk/bin/dartaotruntime
# x64
$ $DART2NATIVE_X64 cpu.dart -o cpu_x64
Generated: [...]/cpu_x64
$ file cpu_x64
cpu_x64: ELF 64-bit LSB shared object, x86-64, [...]
$ ./cpu_x64
Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
# arm
$ $DART2NATIVE_X64 cpu.dart --gen-snapshot $GEN_SNAPSHOT_SIMARM --aot-runtime $DARTAOTRUNTIME_XARM -o cpu_arm
Generated: [...]/cpu_arm
$ file cpu_arm
cpu_arm: ELF 32-bit LSB shared object, ARM, [...]
# on rpi
pi@raspberrypi:~ $ ./cpu_arm
ARMv7 Processor rev 3 (v7l)
它成功了! :)
如果你想让这个问题更容易解决,请在GitHub上为以下问题竖起大拇指。?
通过www.DeepL.com/Translator(免费版)翻译
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!