zhixi-document-runtime/docs/ffi-troubleshooting.md
2026-06-09 19:58:07 +08:00

129 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# FFI Troubleshooting
## UniFFI 版本
本项目使用 UniFFI 0.31,采用 **UDL + proc-macro 混合模式**
- UDL`zx_document.udl`):定义类型和函数签名
- `#[uniffi::export]` proc-macro生成 C ABI 分发符号
- `uniffi-bindgen`:生成 Swift/Kotlin 绑定代码
## 常见问题
### `No such module 'ZxDocumentRuntime'`
**原因**XCFramework 未正确添加到 Xcode 项目。
**解决**
1. 确认 `bindings/ios/ZxDocumentRuntime.xcframework` 已生成
2. 在 Xcode → Target → General → Frameworks 中添加
3. 确保 Embed 设置为 `Do Not Embed`(静态库)
### `Undefined symbol: _ffi_zx_document_ffi_*`
**原因**C ABI 符号未导出。proc-macro 生成的符号名称可能与链接器期望不一致。
**解决**
1. 确认 `crates/zx_document_ffi/src/lib.rs``#[no_mangle] pub extern "C"` 函数存在
2. 检查 Cargo.toml `crate-type = ["lib", "staticlib", "cdylib"]`
3. 运行 `nm target/aarch64-apple-ios/release/libzx_document_ffi.a | grep ffi_` 验证符号
4. 确认 UDL 中声明的函数与 `#[uniffi::export]` 函数名称一致
### `Library not found for -lzx_document_ffi`
**原因**Library Search Paths 未设置。
**解决**
1. Build Settings → Library Search Paths → 添加 `$(PROJECT_DIR)/bindings/ios`
2. 或使用绝对路径指向 `.xcframework` 所在目录
### UniFFI checksum mismatch
**原因**UDL 文件更新后未重新生成 Swift binding。
**解决**
```bash
uniffi-bindgen generate \
--language swift \
--out-dir bindings/ios/generated \
crates/zx_document_ffi/src/zx_document.udl
```
### `setup_scaffolding!()` not called
**原因**`uniffi::setup_scaffolding!()` 必须在 lib.rs 的第一行调用。
**解决**:确认 `crates/zx_document_core/src/lib.rs` 第一行是 `uniffi::setup_scaffolding!();`
### 新增类型/函数后 Swift 不可见
**原因**:只在 Rust 侧添加了类型/函数,但未更新:
1. UDL 文件声明
2. FFI crate `pub use` 重导出
3. Swift binding 重新生成
**完整的 FFI 接入步骤**
```bash
# 1. Rust 侧添加类型 + 函数 + UDL 声明
# 2. FFI crate: pub use 重导出 + #[uniffi::export] 包装
# 3. 重新生成 Swift
uniffi-bindgen generate --language swift \
--out-dir bindings/ios/generated \
crates/zx_document_ffi/src/zx_document.udl
# 4. 验证编译
cargo build --release --target aarch64-apple-ios -p zx_document_ffi
```
### `cargo build` 目标平台不匹配
**原因**macOS 上构建 iOS 目标需要 Apple Silicon target。
**解决**
```bash
rustup target add aarch64-apple-ios aarch64-apple-ios-sim
```
### `infer` / `comrak` / `zip` crate 编译失败
**原因**:某些 crate 在 iOS target 下有 C 依赖。
**解决**
- `comrak`:需要启用 `--features` 中的 `onig` 或使用 `syntect` 后端
- `zip`:纯 Rust无特殊要求
- 确保 `CC` 环境变量指向 Xcode toolchain
### XCFramework 构建注意事项
1. 必须分别编译 device 和 simulator 目标
2. `lipo` 不需要(两个 .a 文件各自是 fat binary
3. header 文件由 `uniffi-bindgen` 生成:`bindings/ios/generated/zx_documentFFI.h`
4. modulemap 文件创建:
```
framework module ZxDocumentRuntime {
header "zx_documentFFI.h"
export *
}
```
### UDL 类型不支持
**问题类型**
- `Vec<(String, &str)>` — 不支持 tuple
- 泛型函数 — 不支持
- 生命周期参数 — 不支持
**解决**:在 FFI 层创建包装类型。例如 `search_pdf_text(&[(u32, &str)])` → FFI 包装为 `search_pdf_pages(Vec<u32>, Vec<String>)`
### Rust 与 iOS 持有引用
UniFFI 生成的对象是 **值类型**(序列化跨 FFI 边界传递不是引用类型。Rust 侧的 `Mutex` 保护全局状态iOS 侧通过函数调用读写状态。
### 验证清单
- [ ] `cargo build --release --target aarch64-apple-ios` 通过
- [ ] `cargo build --release --target aarch64-apple-ios-sim` 通过
- [ ] `nm` 验证 C ABI 符号存在
- [ ] Swift binding 生成并编译通过
- [ ] XCFramework 包含 device + simulator slices
- [ ] header + modulemap 正确
- [ ] demo App 链接成功