|
| 1 | +# Bindgen 设计文档(Python) |
| 2 | + |
| 3 | +本目录目标:使用 Python 实现一个面向 C++ Headers 的 bindgen,自动解析头文件并生成多语言绑定(Dart / Swift / Rust 等)。各语言 API **统一调用 C API**,再由 C API 调用 C++ 实现,确保 ABI 稳定与可移植性。 |
| 4 | + |
| 5 | +本文档说明核心需求、架构、数据模型、生成流程、CLI、可扩展性与里程碑计划。 |
| 6 | + |
| 7 | +## 目标与非目标 |
| 8 | + |
| 9 | +**目标** |
| 10 | + |
| 11 | +- 解析 C++ 公开 API(以头文件为主) |
| 12 | +- 生成多语言 bindings(Dart FFI、Swift bridging、Rust FFI) |
| 13 | +- 所有语言绑定统一调用 C API 层(避免直接绑定 C++ ABI) |
| 14 | +- 统一的中间表示(IR),减少多语言实现成本 |
| 15 | +- 可配置、可扩展、可测试 |
| 16 | +- 与现有仓库结构和 CMake 构建保持良好配合 |
| 17 | + |
| 18 | +**非目标(第一阶段)** |
| 19 | + |
| 20 | +- 不做完整 C++ 语义分析(模板深度推导、宏复杂展开等) |
| 21 | +- 不自动绑定 C++ class 的复杂继承、多态或异常(需经 C API 封装) |
| 22 | +- 不直接生成 GUI/业务层封装,仅做 FFI 级别桥接 |
| 23 | + |
| 24 | +## 总体架构 |
| 25 | + |
| 26 | +```text |
| 27 | +C++ Headers |
| 28 | + | |
| 29 | + v |
| 30 | + Parser (libclang/clang.cindex) |
| 31 | + | |
| 32 | + v |
| 33 | + AST Normalizer |
| 34 | + | |
| 35 | + v |
| 36 | + IR (统一中间表示) |
| 37 | + | |
| 38 | + v |
| 39 | + Code Generator (通用生成器) |
| 40 | + | |
| 41 | + +--------------------+--------------------+--------------------+ |
| 42 | + | | | |
| 43 | + v v v |
| 44 | + Dart Templates Swift Templates Rust Templates |
| 45 | + | | | |
| 46 | + +---------+----------+---------+----------+---------+ |
| 47 | + | | |
| 48 | + v v |
| 49 | + Output bindings (ffi glue per language) |
| 50 | + | |
| 51 | + v |
| 52 | + C API (extern "C") |
| 53 | + | |
| 54 | + v |
| 55 | + C++ Implementation |
| 56 | +``` |
| 57 | + |
| 58 | +- **Parser**:基于 `libclang`/`clang.cindex` 解析头文件,生成 AST |
| 59 | +- **Normalizer**:将 AST 规约为可生成的 IR(类型、函数、常量、结构体) |
| 60 | +- **IR**:语言无关的描述结构 |
| 61 | +- **Code Generator**:通用生成器,负责加载模板与语言映射配置并输出 bindings |
| 62 | +- **Templates**:语言模板 + 语言映射配置(类型映射、命名风格、ABI 约定) |
| 63 | +- **C API**:稳定 ABI 层,`extern "C"` 函数,供所有语言 bindings 调用 |
| 64 | +- **C++ Implementation**:真实实现层,仅由 C API 访问 |
| 65 | + |
| 66 | +## 输入与约束 |
| 67 | + |
| 68 | +- 入口:一组 C++ 头文件 + include paths + compile flags |
| 69 | +- 建议约定宏:用于筛选可导出 API(例如 `NATIVEAPI_EXPORT`) |
| 70 | +- 过滤方式: |
| 71 | + - `export_macro`:只导出带宏标记的符号 |
| 72 | + - `// bindgen:ignore`:显式忽略 |
| 73 | + - 可选白名单/黑名单(按正则匹配函数/类型名) |
| 74 | +- 只处理(MVP): |
| 75 | + - 可导出的 C API 函数(`extern "C"`) |
| 76 | + - `struct` + POD 类型 |
| 77 | + - `enum` 常量 |
| 78 | + - `#define` 的简单常量 |
| 79 | +- 入口头文件推荐指定“主头文件”(统一 include 顺序,避免重复解析) |
| 80 | + |
| 81 | +**约定**:C++ 头文件中的导出 API,必须能映射为 C API(如 `extern "C"` wrapper),bindgen 只对 C API 进行绑定生成。 |
| 82 | + |
| 83 | +## IR 设计 |
| 84 | + |
| 85 | +### 类型系统(IRType) |
| 86 | + |
| 87 | +- 基础类型:`void`, `bool`, `int8/16/32/64`, `uint8/16/32/64`, `float32/64` |
| 88 | +- 扩展基础类型:`size_t`, `ssize_t`, `intptr`, `uintptr` |
| 89 | +- 类型别名:`typedef/using` 归一化为 `alias` |
| 90 | +- 指针类型:`pointer<T>` |
| 91 | +- 数组类型:`array<T, N>` |
| 92 | +- 结构体:`struct { fields }` |
| 93 | +- 枚举:`enum { values }` |
| 94 | +- 字符串:`char*` 规范化为 `cstring` |
| 95 | +- 函数指针:`fnptr(ret, params)`(MVP 可忽略,后续支持) |
| 96 | +- 限定符:`const/volatile` 记录在 `qualifiers` |
| 97 | +- C++ `enum class` 归一化为 `enum`(保留 `scoped` 标记) |
| 98 | + |
| 99 | +### 函数(IRFunction) |
| 100 | + |
| 101 | +- 名称、返回类型、参数列表 |
| 102 | +- 参数可包含 `in/out` 注解 |
| 103 | +- 支持 `nullable` 标注 |
| 104 | +- 可记录 `callconv` 与 `variadic`(默认不支持变参) |
| 105 | + |
| 106 | +### 模块(IRModule) |
| 107 | + |
| 108 | +- headers |
| 109 | +- types |
| 110 | +- functions |
| 111 | +- constants |
| 112 | +- aliases |
| 113 | + |
| 114 | +### IR JSON 示例(最小) |
| 115 | + |
| 116 | +```json |
| 117 | +{ |
| 118 | + "headers": ["include/nativeapi.h"], |
| 119 | + "types": [ |
| 120 | + { |
| 121 | + "kind": "struct", |
| 122 | + "name": "Point", |
| 123 | + "fields": [ |
| 124 | + {"name": "x", "type": {"kind": "float32"}}, |
| 125 | + {"name": "y", "type": {"kind": "float32"}} |
| 126 | + ] |
| 127 | + } |
| 128 | + ], |
| 129 | + "functions": [ |
| 130 | + { |
| 131 | + "name": "na_distance", |
| 132 | + "return_type": {"kind": "float32"}, |
| 133 | + "params": [ |
| 134 | + {"name": "a", "type": {"kind": "pointer", "to": {"kind": "struct", "name": "Point"}}, "nullable": false}, |
| 135 | + {"name": "b", "type": {"kind": "pointer", "to": {"kind": "struct", "name": "Point"}}, "nullable": false} |
| 136 | + ] |
| 137 | + } |
| 138 | + ], |
| 139 | + "constants": [ |
| 140 | + {"name": "NA_OK", "type": {"kind": "int32"}, "value": 0} |
| 141 | + ], |
| 142 | + "aliases": [ |
| 143 | + {"name": "NAHandle", "target": {"kind": "uintptr"}} |
| 144 | + ] |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +## 代码生成策略 |
| 149 | + |
| 150 | +**绑定链路约束** |
| 151 | + |
| 152 | +- 生成的 Dart/Swift/Rust bindings **只调用 C API**,不直接依赖 C++ 符号 |
| 153 | +- C API 负责:参数规约、ABI 稳定、与 C++ 实现交互 |
| 154 | +- C++ 实现层可自由演进,但对外 ABI 需保持稳定 |
| 155 | + |
| 156 | +## 通用模板生成器设计 |
| 157 | + |
| 158 | +Generator 可以做成通用的模板渲染器,通过“语言模板 + 语言映射配置”驱动输出,不把语言差异硬编码在 Python 里。 |
| 159 | + |
| 160 | +**设计原则** |
| 161 | + |
| 162 | +- 生成器只做:加载 IR → 选择语言 → 渲染模板 → 写文件 |
| 163 | +- 语言差异放在模板与映射配置(类型映射、命名风格、调用约定) |
| 164 | +- 复杂逻辑尽量前置到 Normalizer(保证模板尽量“无脑”) |
| 165 | +- 模板约定:模板依赖的上下文字段必须稳定并有文档 |
| 166 | + |
| 167 | +**目录结构(建议)** |
| 168 | + |
| 169 | +``` |
| 170 | +tools/bindgen/ |
| 171 | + parser.py # 解析 C/C++ headers -> AST |
| 172 | + normalizer.py # AST -> IR 规约 |
| 173 | + ir/ |
| 174 | + model.py # IR 数据结构 |
| 175 | + serializer.py # IR JSON 读写 |
| 176 | + codegen/ |
| 177 | + generator.py # 通用生成器入口 |
| 178 | + context.py # 模板上下文构建 |
| 179 | + templates/ |
| 180 | + dart/ |
| 181 | + bindings.j2 |
| 182 | + helpers.j2 |
| 183 | + lang.yaml |
| 184 | + swift/ |
| 185 | + bindings.j2 |
| 186 | + modulemap.j2 |
| 187 | + lang.yaml |
| 188 | + rust/ |
| 189 | + bindings.j2 |
| 190 | + lib.j2 |
| 191 | + lang.yaml |
| 192 | +``` |
| 193 | + |
| 194 | +**语言映射配置(示例)** |
| 195 | + |
| 196 | +```yaml |
| 197 | +language: dart |
| 198 | +types: |
| 199 | + void: Void |
| 200 | + int32: Int32 |
| 201 | + uint32: Uint32 |
| 202 | + float32: Float |
| 203 | + cstring: Pointer<Utf8> |
| 204 | +conventions: |
| 205 | + enum_as_int: true |
| 206 | + struct_layout: ffi.Struct |
| 207 | + callconv: native |
| 208 | +naming: |
| 209 | + function: camel |
| 210 | + constant: upper_snake |
| 211 | +``` |
| 212 | +
|
| 213 | +**通用生成器伪代码** |
| 214 | +
|
| 215 | +```python |
| 216 | +ir = load_ir(...) |
| 217 | +lang = load_lang_config(...) |
| 218 | +templates = load_templates(lang) |
| 219 | +context = build_context(ir, lang) |
| 220 | +render_to_files(templates, context, out_dir) |
| 221 | +``` |
| 222 | + |
| 223 | +**模板上下文约定(建议)** |
| 224 | + |
| 225 | +- `module`: 当前模块信息(headers, namespaces) |
| 226 | +- `types`: 结构体/枚举/别名列表(已排序) |
| 227 | +- `functions`: 函数列表(已过滤) |
| 228 | +- `constants`: 常量列表 |
| 229 | +- `mapping`: 语言映射配置(types/conventions/naming) |
| 230 | +- `helpers`: 预计算字段(如 dart ffi 类型名、rust type 名) |
| 231 | + |
| 232 | +**优点** |
| 233 | + |
| 234 | +- 新增语言只需新增模板 + 映射配置 |
| 235 | +- 语言差异集中可见,维护成本低 |
| 236 | +- 测试可按模板/映射分层 |
| 237 | + |
| 238 | +### Dart |
| 239 | + |
| 240 | +- 生成 `ffi.DynamicLibrary` + `typedef` + `lookupFunction` |
| 241 | +- `struct` 映射为 `ffi.Struct` |
| 242 | +- `enum` 映射为 `int` |
| 243 | +- `cstring` -> `Pointer<Utf8>` + helper |
| 244 | +- 输出文件(建议):`bindings.dart`, `helpers.dart` |
| 245 | + |
| 246 | +### Swift |
| 247 | + |
| 248 | +- C header 生成 module map(如需) |
| 249 | +- `struct` 使用 `@frozen struct` 或 `UnsafePointer` |
| 250 | +- `enum` -> Swift `enum` with rawValue |
| 251 | +- 暴露 C 函数桥接层 |
| 252 | +- 输出文件(建议):`Bindings.swift`, `module.modulemap`(可选) |
| 253 | + |
| 254 | +### Rust |
| 255 | + |
| 256 | +- 生成 `extern "C"` block |
| 257 | +- `struct` -> `#[repr(C)] struct` |
| 258 | +- `enum` -> `#[repr(C)] enum` or `type alias` for constants |
| 259 | +- `cstring` -> `*const c_char` |
| 260 | +- 输出文件(建议):`lib.rs`, `bindings.rs` |
| 261 | + |
| 262 | +## 配置与注解 |
| 263 | + |
| 264 | +### YAML 配置文件 |
| 265 | + |
| 266 | +```yaml |
| 267 | +entry_headers: |
| 268 | + - include/nativeapi.h |
| 269 | +include_paths: |
| 270 | + - include |
| 271 | +clang_flags: |
| 272 | + - -std=c11 |
| 273 | + - -DNATIVEAPI_EXPORT |
| 274 | +languages: |
| 275 | + - dart |
| 276 | + - swift |
| 277 | + - rust |
| 278 | +filters: |
| 279 | + export_macro: NATIVEAPI_EXPORT |
| 280 | + allowlist_regex: [] |
| 281 | + denylist_regex: [] |
| 282 | +platform: |
| 283 | + os: macos |
| 284 | + abi: clang |
| 285 | +``` |
| 286 | +
|
| 287 | +### 注解建议(可扩展) |
| 288 | +
|
| 289 | +- 使用宏或注释标注 API,如: |
| 290 | + - `NATIVEAPI_EXPORT` 标记导出 |
| 291 | + - `// bindgen:ignore` 跳过 |
| 292 | + - `// bindgen:nullable` 标记可为空 |
| 293 | + - `// bindgen:rename <NewName>` 重命名 |
| 294 | + |
| 295 | +## CLI 设计 |
| 296 | + |
| 297 | +``` |
| 298 | +PYTHONPATH=tools python -m bindgen \ |
| 299 | + --config tools/bindgen/bindgen.yaml \ |
| 300 | + --out tools/bindgen/out |
| 301 | +``` |
| 302 | +
|
| 303 | +常用参数: |
| 304 | +
|
| 305 | +- `--config` 配置文件 |
| 306 | +- `--out` 输出目录 |
| 307 | +- `--lang` 指定语言(可覆盖配置) |
| 308 | +- `--dump-ir` 输出 IR JSON 便于调试 |
| 309 | +- `--platform` 指定平台(如 `windows-msvc`、`linux-gnu`、`macos-clang`) |
| 310 | +
|
| 311 | +## 开发计划(里程碑) |
| 312 | +
|
| 313 | +1. **MVP** |
| 314 | + - 支持解析函数 + 基础类型 |
| 315 | + - 生成 Dart bindings |
| 316 | + - IR JSON dump |
| 317 | + - 最小可用示例(单头文件 -> bindings) |
| 318 | +
|
| 319 | +2. **扩展** |
| 320 | + - 支持 struct、enum |
| 321 | + - 生成 Swift/Rust bindings |
| 322 | +
|
| 323 | +3. **增强** |
| 324 | + - 增加注解/宏过滤 |
| 325 | + - 增加类型映射配置 |
| 326 | +
|
| 327 | +4. **稳定化** |
| 328 | + - 兼容性测试 |
| 329 | + - CI 脚本 |
| 330 | +
|
| 331 | +## 关键技术点 |
| 332 | +
|
| 333 | +- `libclang` 解析:需要确保 clang 能找到 include paths |
| 334 | +- 类型映射:不同语言对 `size_t`, `bool` 的对应关系不一致 |
| 335 | +- ABI 兼容:必须保证 `repr(C)`/`ffi.Struct` 对齐一致 |
| 336 | +
|
| 337 | +## 风险与规避 |
| 338 | +
|
| 339 | +- **宏复杂度高**:MVP 仅处理简单宏与 export 宏 |
| 340 | +- **C++ 语义**:默认 `extern "C"` 入口 |
| 341 | +- **跨平台 ABI**:需在生成器中区分平台(Windows/Linux/macOS) |
| 342 | +
|
| 343 | +## 下一步 |
| 344 | +
|
| 345 | +- 补充 `bindgen.yaml` 示例 |
| 346 | +- 实现 `parser.py` 与 `ir.py` 的最小骨架 |
| 347 | +- 选择模板引擎(如 `jinja2`)用于 codegen |
0 commit comments