10.2. 直接运行字节码

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

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

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

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

10.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

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

10.2.2. 使用库文件

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

PikaObj *pikaScriptInit(void){
...
    __pikaMain = newRootObj("pikaMain", New_PikaMain);
    extern unsigned char pikaModules_py_a[];
    obj_linkLibrary(__pikaMain, pikaModules_py_a);
...
}

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

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

obj_runModule(__pikaMain, "main");

10.2.3. 运行单个字节码

将单个字节码文件 .py.o 中的数据,传入 pikaVM_runByteCode() API可以就直接运行单个字节码,可以参考g030中从字节码启动的用法。 https://gitee.com/Lyon1998/pikapython/blob/master/bsp/stm32g030c8/Booter/main.c

注意

  1. pikaVM_runByteCode() API 运行的字节码必须是 const 类型,如果字节码不是 const,则需要使用 pikaVM_runByteCodeInconstant()

  2. 如果已经对接了文件系统,可以使用 pikaVM_runByteCodeFile() API 直接运行 .py.o 文件。

  3. pikaVM_runByteCodeInconstant()pikaVM_runByteCodeFile() 需要内核版本 >=v1.11.7