不是手写 glue
C 库作者写 `.lnb`,生成器负责参数检查、类型转换、错误码处理、C glue 和注册入口。
LNS Binding
LNB 是 LNS 的声明库文件:用一份小而明确的接口描述,把 C 函数变成可授权、可审计、可生成绑定代码的 LNS API。
C 库作者写 `.lnb`,生成器负责参数检查、类型转换、错误码处理、C glue 和注册入口。
LNB 生成 `api { extern ... }` 契约。脚本只能 import 契约里公开的能力,宿主仍按 capability 授权。
C 指针、设备对象、连接对象等统一映射成 LNS `handle`,不暴露裸 C 类型。
原始 C 函数通常命名长、类型复杂、错误返回不统一。LNB 把它们整理成稳定的 LNS API。
同一份 LNB 能生成契约、glue、init 注册函数,避免每个库都手写重复边界代码。
设备、游戏、网关、自动化工具可以只开放选定 capability,而不是把系统能力整体暴露给用户。
LNB 不参与运行时执行。它是生成源:从同名 C 头读取符号,再按 LNB 规则生成 LNS 契约和 C 边界代码。
mylib.lnb ──自动匹配──► mylib.h
│
▼
lnbind / lnbgen
│
├─ trusted/lib/mylib.lns
├─ mylib_glue.c
└─ mylib_init.c
`bindings/mylib.lnb` 默认查找 `bindings/mylib.h`。LNB 文件里不写头文件路径;多头依赖由 `mylib.h` 自己 include。
绑定源文件名就是约定。这样减少配置项,也避免接口文件和头文件路径漂移。
普通 C 头文件,不依赖 LNS 语法。
int mylib_starts(void);
double mylib_add(double a, double b);
const char* mylib_name(void);
int mylib_set_led(int pin, int on);
typedef struct Device Device;
Device* device_open(const char* id);
int device_close(Device* device);
声明 C 函数如何映射成 LNS API。
option module = "mylib";
option output_contract = "trusted/lib/mylib.lns";
option output_glue = "mylib_glue.c";
option output_init = "mylib_init.c";
option init_name = "lnlib_init_mylib";
api "mylib" {
starts : int = mylib_starts();
add : num = mylib_add(num a, num b);
name : str = mylib_name() @nonnull;
set_led : int! = mylib_set_led(int pin, int on);
}
api "device" {
open : handle = device_open(str id) @handle("Device") @borrowed;
close : int! = device_close(handle device) @handle("Device");
}
声明生成产物名称,例如模块名、契约路径、glue 文件、注册入口函数名。
每个 `api "cap"` 对应一个 LNS capability。块内左侧是脚本函数名,右侧是 C 符号。
`@nonnull`、`@handle("Device")`、`@borrowed` 等属性补充转换策略,不污染 LNS 脚本语法。
api "mylib" {
脚本函数名 : LNS返回类型 = C函数名(LNS参数类型 参数名) @属性;
add : num = mylib_add(num a, num b);
set_led : int! = mylib_set_led(int pin, int on);
}
`int` 要求有限整数并检查 C 目标范围;`num` 转 double;`float/double` 按浮点规则转换。
`str` 可转 `const char*` 或 `const ln_str*`。C 返回 NULL 时按规则抛错或按属性映射。
`int!` 表示 C 返回 0 成功、非 0 失败。LNS 侧生成 `extern void`,失败进入异常/pcall 流程。
LNB 不暴露裸 C 指针类型。设备对象、连接对象、图像对象、文件句柄等都以 LNS `handle` 表示。脚本只能保存和回传 handle,不能访问 C 对象内部。
api "device" {
open : handle = device_open(str id)
@handle("Device") @borrowed;
close : int! = device_close(handle device)
@handle("Device");
}
api "mylib" {
extern int starts();
extern num add(num a, num b);
extern str name();
extern void set_led(int pin, int on);
}
api "device" {
extern handle open(str id);
extern void close(handle device);
}
import mylib;
import device;
function main() {
var total = mylib.add(1, 2);
var d = device.open("motor-1");
mylib.set_led(4, 1);
device.close(d);
return mylib.name() + ": " + total;
}