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

4.0 KiB
Raw Blame History

FFI Troubleshooting

UniFFI 版本

本项目使用 UniFFI 0.31,采用 UDL + proc-macro 混合模式

  • UDLzx_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。

解决

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 接入步骤

# 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。

解决

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 链接成功