# MoonBind 0.2：可维护的 C 库绑定

0.2 让“生成一次绑定”成为可重复的项目流程：配置生成规则、检测手工修改、检查产物是否过期，并在 C 库升级时查看接口变化。

## 项目配置

仓库根目录提供可运行的 `moonbind.example.json`：

```sh
moon run cmd/main --target wasm-gc -- --config moonbind.example.json
moon run cmd/main --target wasm-gc -- --config moonbind.example.json --check
```

```json
{
  "header": "examples/greet/greet.h",
  "out": "_build/greet-v02",
  "target": "x86_64",
  "include_paths": [],
  "defines": [],
  "allow_functions": ["greet_version", "greet_open", "greet_close"],
  "rename_functions": {"greet_version": "version"},
  "native_sources": ["../../examples/greet/greet.c"]
}
```

- `header` 必填。`header`、`out`、`include_paths` 相对于配置文件所在目录解析。
- `native_sources` 相对于生成包所在目录，写入 `native-stub`；源文件不会被复制。`stub.c` 自动加入。
- 未设置或空的 `allow_functions` 表示选择所有外部函数。非空时使用 C 函数名精确匹配；类型和常量仍会保留。拼错函数名会报错。
- `rename_functions` 只改 MoonBit 函数名，保持 C 链接符号不变。无效名称、未选择的函数、重名冲突会报错。
- 命令行中的标量覆盖配置值，数组选项追加，重命名按 C 名覆盖。
- 使用 `--config` 时，头文件只能在配置中指定；不能再传位置参数。
- 未知字段、重复 JSON 键和错误类型均会报错。

命令行也提供 `--allow <C函数名>`、`--rename <C名=MoonBit名>`、`--native-source <路径>`，可以重复使用。

## 安全更新与 CI 检查

生成目录包含：

```text
bindings.mbt
strings.mbt
stub.c
moon.pkg
moonbind-report.json
.moonbind-state.json
```

状态文件保存上一次生成的完整内容，作为检测手工修改的基线；建议与绑定一并提交到版本控制。

再次生成时，工具先检查所有受管理文件。文件与上次生成结果不同、且不等于本次应生成内容时，会在写入前报错。陌生目录中的同名文件也会受到保护。其他文件（如 `wrapper.mbt`）不受生成器管理。

发现冲突后，请保留自己的修改，在新目录生成并对比迁移。没有自动覆盖用户修改的 `--force`。对于旧版手改过的 `moon.pkg`，应将 C 源文件配置移入 `native_sources`。

```sh
moon run cmd/main --target wasm-gc -- --config moonbind.example.json --check
```

`--check` 不创建目录、不更新文件；产物或状态缺失、过期或有冲突时返回非零退出码。它适用于 CI 检查“头文件改了但绑定忘记更新”的情况。

普通写入错误会触发尽力回滚。多文件写入并不是文件系统事务，不能保证断电恢复，也不支持多个生成器同时写同一目录。

## 查看结构化报告

```sh
moon run cmd/main --target wasm-gc -- examples/greet/greet.h --json
```

报告区分：

- 函数 `generated`：生成了绑定。
- 函数 `skipped`：无法生成，并记录原因。
- 函数 `excluded`：被函数筛选配置排除。
- 结构体 `mirrored` / `opaque`：直接映射或以不透明类型处理。

生成报告包括配置上下文、目标 ABI、版本、函数签名和统计。使用 `--out` 时保存为 `moonbind-report.json`。`--json` 在错误时输出 `status: "failed"` 和错误信息，并保留非零退出码。编译器本身可能在运行 CLI 前输出诊断，脚本应同时检查进程退出状态。

报告只描述解析器实际识别出的声明；它不能证明完整覆盖所有 C 扩展或函数式宏。

## 比较两个版本的头文件

直接运行仓库提供的升级示例：

```sh
moon run cmd/main --target wasm-gc -- testdata/upgrade/v2.h --compare testdata/upgrade/v1.h
moon run cmd/main --target wasm-gc -- testdata/upgrade/v2.h --compare testdata/upgrade/v1.h --json
```

这里位置参数是新版，`--compare` 参数是旧版。工具会发现：

- `Packet` 的 `size` 从 `int` 变为 `long`，并增加 `priority` 字段；
- `packet_legacy` 被移除，`packet_reset` 被加入；
- `PACKET_LIMIT` 常量变化；
- `packet_send` 的参数声明未改变，但引用的结构体改变，需复查调用方。

比较覆盖函数签名、结构体成员类型及布局、typedef、enum、已解析的整数常量和绑定支持状态。它也会沿嵌套结构体和指针收集受影响函数。参数改名和注释变化不会被当成函数签名变化。

两份头文件使用相同目标、宏定义和包含路径；头文件自身的相对 include 仍分别从各自目录解析。比较不写绑定，不可与 `--out`、`--check` 或 `--verify` 同用。使用项目配置比较时，会忽略配置中的 `out`。

变化报告是**源码层面的复查提示，不是二进制兼容性保证**。字段通过指针间接使用，也可能被保守地列为受影响；所有权、线程安全、函数行为和未识别语法的变化不在判断范围内。比较成功返回 0，即使发现变化；自动化可解析 `changes` 后采用自己的审核策略。

## 验证

```sh
moon test --target wasm-gc
python scripts/verify-workflow.py
```

黑盒脚本检查配置路径、生成一致性、只检查模式、冲突前置检测、状态文件损坏、函数筛选和重命名、JSON 错误报告及接口对比。

Linux 环境中安装 C 编译器及 zlib 开发包后执行：

```sh
python3 scripts/verify-workflow.py --native
bash scripts/verify-layout.sh
```

原生验证在新的临时项目中重新生成绑定，随后：

1. 编译链接仓库 SQLite 实现，写入并查询 3 条记录；
2. 从 zlib 1.3.1 官方头文件生成绑定，链接系统 zlib，比较实际 `adler32` 结果与 Python zlib。

测试产物保存在 `_build/workflow-*`，便于检查生成结果和升级报告。该覆盖范围是 Linux x86-64 的这两个调用场景，不等于所有平台和全部库接口均已运行验证。
