8.2. 直接运行字节码

PikaScript 的运行时架构如下图所示,在默认情况下,Python 脚本解析成 Pika 字节码的过程是放在 MCU 执行的,这使得 MCU 可以直接运行 Python 脚本,包括支持交互式运行。

而在资源受限的情况下,可以将 Python 脚本解析为字节码的过程在 PC 提前完成,在 MCU 中直接执行 Pika 字节码,这样一来 解析 Python 脚本的代码就可以被裁剪掉了

在代码中避免使用 obj_run() 执行 python 脚本,编译器就会自动优化掉 Python 解析的代码,降低代码体积占用。

_images/1639281281608-011ffd89-5851-47d8-9dca-438ed963f5d4-164649975346225.png

8.2.1. 在 PC 上将 Python 转为字节码:

预编译器 rust-msc-latest-win10.exe 集成了字节码生成器,在预编译时会将 main.py 和被 main.py import (包括间接 import) 的 .py 文件编译为字节码,生成的字节码文件在 pikascript-api 文件夹下。

.py 文件会被生成为 .py.o 字节码文件,例如 main.py 会生成 pikascript-api/main.py.o

同时,所有的 .py.o 文件会被自动打包成一个库文件 pikascript-api/pikaModules.py.a,库文件中包含了所有的字节码文件。

_images/image-20220823155644618-16612416630901-16612416855853.png

为了方便编译固件时在 mcu 中载入库文件,预编译器还会把库文件自动转换为 C 的字节数组文件 pikascript-api/__asset_pikaModules_py_a.c

  1. /* __asset_pikaModules_py_a.c */
  2. #include "PikaPlatform.h"
  3. /* warning: auto generated file, please do not modify */
  4. PIKA_BYTECODE_ALIGN const unsigned char pikaModules_py_a[] = {
  5. 0x7f, 0x70, 0x79, 0x61, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  6. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  7. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,
  8. ...

8.2.2. 使用库文件

使用 obj_linkLibrary() API 可以导入库文件,参考自动生成的 pikaScriptInit()

  1. PikaObj *pikaScriptInit(void){
  2. ...
  3. __pikaMain = newRootObj("pikaMain", New_PikaMain);
  4. extern unsigned char pikaModules_py_a[];
  5. obj_linkLibrary(__pikaMain, pikaModules_py_a);
  6. ...
  7. }

导入库文件后,即可直接在 python 脚本里面 import 库文件中包含的模块。

也可以直接将一个模块作为脚本运行,如:

  1. obj_runModule(__pikaMain, "main");

8.2.3. 运行单个字节码

从单个字节码文件 .py.o 中读取数据,然后使用 pikaVM_runByteCode() API可以就直接运行单个字节码,可以参考g030中从字节码启动的用法。

https://gitee.com/Lyon1998/pikascript/blob/master/bsp/stm32g030c8/Booter/main.c