扩展运行机制
扩展运行机制
功能
扩展机制把“脚本能看到的 API”和“扩展内部如何执行”分开。脚本只通过 bindings.json 里声明的入口、对象和方法调用扩展;BT 宿主负责加载 .bts 包、校验描述文件、建立注册表,并把调用分发给对应 Runner。
语法
扩展入口调用语法和普通函数一致:
object = calc(1) value = object.add(2).value() // 输出:3 print value
calc 来自 bindings.json 的公开入口声明,add 和 value 来自对象方法声明。
参数
扩展调用的参数由 bindings 决定。宿主会按 bindings 的参数数量、类型和 role 处理脚本传入的值,再把调用交给对应 Runner。
返回值
扩展调用可以返回原始值,也可以返回扩展对象句柄。对象句柄只表示“某个扩展模块中的某个对象”,真实状态由扩展后端保存。
加载流程
项目启动时,BT 会按以下流程处理扩展:
1. 查找项目根目录下的 extensions/。
2. 按文件名顺序读取目录中的 .bts 文件。
3. 校验 .bts 后缀、zip 条目路径、条目数量、单文件大小和总解压大小。
4. 读取并校验 manifest.json。
5. 读取并校验 bindings.json。
6. 根据 manifest.kind 初始化纯 BT Runner 或 WASM Runner。
7. 建立扩展注册表,检查公开入口名是否冲突。
8. 把公开入口注入到当前 VM 的用户全局环境。
加载失败时,项目启动会失败并输出中文错误;BT 不会加载半成功的扩展包。
调用流程
脚本调用扩展入口时:
宿主会按入口名 calc 找到 bindings 中的函数声明,检查参数数量和类型,再把调用交给扩展所属 Runner。返回值如果是普通值,就直接回到脚本;如果是扩展对象,脚本拿到的是一个受宿主管理的对象句柄。
脚本调用对象方法时,宿主会先根据对象句柄找到扩展模块和对象类型,再查找方法名。WASM 方法调用时,接收者对象句柄会作为第一个参数传给 WASM;纯 BT 方法调用时,宿主会在内部 VM 中把方法调用到对应对象上。
kind 和 abi
kind 是后端类型,决定入口文件由谁执行。abi 是调用协议版本,决定宿主和后端如何交换参数、返回值和对象句柄。
| kind | abi | Runner |
|---|---|---|
bt | bts-bt-1 | 纯 BT Runner,复用 BT Parser、Compiler 和 VM。 |
wasm | bts-wasi-1 | WASM Runner,使用 WASI P1 和 BtValueBinary。 |
这两个字段不能随意组合。kind=bt 必须使用 bts-bt-1,kind=wasm 必须使用 bts-wasi-1。
代码示例
同一个 bindings.json 风格可以对应不同后端。脚本侧调用保持一致:
value = calc(4).add(6).value() // 输出:10 print value
差别只在扩展包内部:纯 BT 扩展由 src/lib.bt 实现;WASM 扩展由 module.wasm 实现。
注意事项
- 公开入口会成为全局常量,脚本不能重新赋值。
-
env('calc')可以读取扩展入口,has_env('calc')返回true。 -
envs('calc')和has_envs('calc')只表示系统函数和系统常量,不会把扩展入口当作系统能力。 - 扩展入口名不能和 BT 系统环境名称冲突,也不能和其他扩展入口重复。
- 扩展对象不应跨越不支持对象句柄的边界,例如
task()快照。