关于 rust-uniffi-building
这项技能用于围绕 Rust 库设计、生成、集成和验证 Mozilla UniFFI 绑定,面向需要向宿主语言开放共享 Rust 逻辑的开发者,并覆盖绑定、原生制品与打包契约。
主要功能
- 01选择 UDL 或过程宏方案
- 02设计适配宿主语言的 API
- 03为目标语言生成绑定
- 04验证 Rust 与宿主语言构建
- 05检查打包和原生库加载
- 06诊断绑定及运行时故障
适用场景
- 01向 Kotlin 或 Swift 开放 Rust 库逻辑
- 02生成并集成 UniFFI 绑定
- 03在消费项目中验证原生包
- 04排查绑定生成或加载错误
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ full-stack-skills/ rust-skills --skill rust-uniffi-building安装后在 Claude Code 中输入/rust-uniffi-building确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlexamples/examples.mdexamples/golden-uniffi/Cargo.tomlexamples/golden-uniffi/src/lib.rsreferences/async-lifetimes-and-callbacks.mdinterface-model.mdinternals-and-diagnostics.mdlanguage-bindings.mdofficial-doc-map.mdscaffolding-and-generation.mdtesting-packaging-and-upgrades.md详细介绍
Rust UniFFI 构建
围绕共享 Rust 库构建范围明确、版本化的跨语言 API。即使用户没有提到 UniFFI,也要将“用 Rust 编写核心逻辑,一次支持 Swift 和 Android”“从 Kotlin 和 iOS 调用 Rust”或“在移动端和浏览器客户端之间复用 Rust 业务逻辑”等请求识别为 UniFFI 评估/构建任务。应将生成的绑定、编译后的原生库和宿主语言打包视为一个整体契约:仅成功构建 Rust,并不能证明 Kotlin、Swift、Python、Ruby、JavaScript 或 WASM 消费端能够正常工作。
范围与路由
将此技能用于 Mozilla UniFFI 接口设计、脚手架、绑定生成、语言集成、生命周期行为和端到端验证。
有意识地将相邻任务路由到以下技能:
- 手写
extern "C"、裸指针、分配器所有权或手动编写头文件 →rust-unsafe-ffi。 - 通用过程宏实现或诊断 →
rust-macros。 - 工作区清单、构建脚本、功能、交叉编译和产物配置 →
rust-cargo-build。 - 导出异步调用以外的 Rust 任务监管和运行时架构 →
rust-concurrency。 - 通用测试策略、覆盖率或模糊测试基础设施 →
rust-testing。
工作流
1. 明确实际契约
编辑前,记录:
rustc --version --verbose、目标三元组、MSRV 和宿主平台;- 锁定的
uniffi、后端和语言工具版本,以及已启用的功能; - 目标语言,以及 Kotlin/JVM、Android、Swift、Xcode、Python、Ruby 或 WASM 的最低版本;
- 库产物类型、包名、命名空间/模块名和加载路径;
- 导出的函数、对象、记录、枚举、错误、trait、回调、异步调用和自定义类型;
- 线程、取消、所有权、销毁和向后兼容性预期;
- 生成责任方:Cargo 构建、纳入版本控制的工具、Gradle/Xcode 任务、CI 作业或发布流水线。
检查 Cargo.lock 和当前官方 UniFFI 指南。不要照搬其他 UniFFI 发布系列中的语法。仓库的标准示例只能作为其锁定版本的依据,不能视为永不过时的依赖建议。
2. 选择一种接口定义策略
| 策略 | 适用情况 | 必须遵循的规范 |
|---|---|---|
| 过程宏 | Rust 是 API 的唯一事实来源,且支持的构造涵盖该契约 | 使用库模式,并且只调用一次 uniffi::setup_scaffolding!() |
| UDL | 需要明确的语言无关模式,或必须以现有 UDL 为准 | 在 build.rs 中生成,并包含生成的脚手架 |
| UDL + 宏混用 | 迁移期间,或确实需要同时使用两者才能支持某个构造 | 确保 UDL 单独有效;使 crate 名称与 UDL 命名空间一致 |
不要在同一个 crate 中同时调用 uniffi::setup_scaffolding!() 和 uniffi::include_scaffolding!()。不要只为方便而混用策略;这会增加重复定义和漂移风险。
在设计公开类型或选择 UDL 与宏之前,请阅读接口模型。
3. 建立脚手架和产物边界
对于仅使用过程宏的 crate,请从最精简的可行模式开始:
uniffi::setup_scaffolding!();
#[derive(uniffi::Record)]
pub struct Greeting {
pub message: String,
}
#[uniffi::export]
pub fn greet(name: String) -> Greeting {
Greeting {
message: format!("Hello, {name}!"),
}
}
为 Rust 调用方和宿主所需的平台构建普通 Rust 库产物:
[lib]
crate-type = ["lib", "cdylib", "staticlib"]
不要自动启用所有 crate 类型或 UniFFI 功能。根据宿主打包契约选择产物;实际可行时,将 bindgen/CLI 依赖隔离开,并尽量精简面向运行时的依赖。
关于 UDL 构建脚本、生成的绑定、配置优先级和库模式命令,请阅读脚手架与生成。
4. 设计符合 FFI 形态的公共 API
- 仅导出 UniFFI 支持的类型,或显式定义自定义/外部转换。
- 不可变值传递优先使用记录类型;需要身份标识或共享状态时使用对象。
- 如果所选 UniFFI 版本有要求,导出的对象构造函数应返回
Arc<Self>。 - 将预期失败建模为导出的错误枚举;绝不要用 panic 表示常规失败。
- 将内部 Rust 类型设为私有,并在 UniFFI 边界处进行转换。
- 将名称、字段是否存在、枚举变体、默认值和错误变体视为影响宿主语言兼容性的约定。
- 限制字符串、字节缓冲区、集合、递归结构、回调频率和响应大小。
- 避免暴露以 Rust 为中心的 API,以免在每种目标语言中都显得难用或不安全。
导出 futures、回调、trait 或有状态对象之前,请阅读 异步、生命周期与回调。
5. 按语言生成并集成
根据将要发布的确切库/配置组合生成绑定。保持生成的源代码与原生构件版本一致。
不要止步于生成文件;还要验证特定语言的集成:
- Kotlin/Android:包/JNA 或平台桥接、Gradle 任务输入、ABI 拆分、协程行为和原生库加载;
- Swift/Apple:Swift 源文件、头文件/模块映射、静态或动态库链接、模块命名、Xcode 构建阶段和 XCFramework 打包;
- Python:扩展/库发现、生成模块导入、支持的 Python 版本以及 wheel/平台标签;
- Ruby:生成的包装器加载,以及所选发行版文档中说明的功能缺口;
- WASM:不稳定支持的限制、单线程假设、JavaScript 工具链以及支持的 UniFFI 功能。
仅针对所请求的目标语言阅读 语言绑定。
6. 在三个边界进行验证
先运行 Rust 检查:
cargo fmt --all --check
cargo check --workspace --all-targets --all-features
cargo test --workspace --all-targets --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings
然后验证:
- 生成边界——从干净的代码检出中可以确定性地重新生成绑定;遇到元数据、命名空间、配置或库不匹配时,会清楚地报错。
- 宿主语言边界——针对生成的原生构件,编译并运行真实的 Kotlin、Swift、Python、Ruby 或 WASM 测试。
- 分发边界——将包安装到最小化的使用方项目中,并在受支持的平台上验证加载、调用、错误、回调、异步取消和清理。
Rust 测试、生成源代码快照和宿主语言编译,代表不同层级的证据。未经实际执行,不要声称某个平台可用。
发布、设计 CI 或迁移版本之前,请阅读 测试、打包与升级。
7. 从正确的层级诊断
更改代码前,先对故障进行分类:
| 症状 | 首先检查 |
|---|---|
| 缺少导出符号或元数据 | 脚手架宏/include 模式、crate 功能、最终库构件 |
| 符号或定义重复 | 混用 UDL/宏、重复的脚手架设置、多个生成源 |
| Bindgen 找不到 crate/配置 | cargo-metadata、全局 [crate-roots]、工作目录、配置优先级 |
| 生成代码可编译,但库无法加载 | 文件名、架构、ABI、搜索路径、签名、包内容 |
| 值损坏或无法解码 | 类型模型、自定义转换器、版本不一致、lowering/lifting 契约 |
| 对象消失、泄漏或发生竞争 | 引用计数、宿主生命周期、回调注册、线程策略 |
| 异步操作挂起或取消后仍泄漏工作 | runtime 功能、外部执行器/轮询器、取消与完成契约 |
| 仅发布构建失败 | 死代码剥离、LTO、符号保留、功能/构建配置差异 |
仅当表层检查无法解释故障时,才阅读 内部机制与诊断。
注意事项
- UniFFI 会生成绑定;它不会为每个平台打包、签名、发布或加载原生库。
- 生成的绑定和 Rust 构建产物必须来自兼容的 UniFFI 元数据和配置。
latest文档可能会变动。请固定 crate 版本,并记录用于发布决策的指南快照。- 即使宏添加了受支持的条目,UDL 文件仍然是完整的架构定义。
- 必要时,将
#[cfg]放在单独的导出 impl 块上;导出块内的条件条目仍可能生成不兼容的脚手架代码。 - 宿主语言的命名、异常、可空性、集合和生命周期语义与 Rust 并不完全相同。
- Miri 无法验证真实的外部运行时。可用它检查 Rust 侧的不安全代码,然后运行平台集成测试。
何时不应使用
以下情况不要启用此技能:
- 不涉及外部语言使用者的普通 Rust 库 API;
wasm-bindgen、CXX、PyO3、JNI、cbindgen、Diplomat 或原始 C 绑定,除非任务明确采用或比较 UniFFI;- 编写与 UniFFI 无关的通用 derive 或属性宏;
- 在不涉及 UniFFI 契约、代码或构建产物变更时,为已生成的绑定打包。
完成标准
- 固定版本、目标平台、语言、生成负责人以及构建产物/软件包契约。
- 选择过程宏、UDL 或有充分依据的混合策略,避免生成重复的脚手架代码。
- 明确导出类型、错误、所有权、回调、异步和兼容性模型。
- 使用确切的待发布库及配置生成绑定。
- 通过 Rust 检查,并针对每个声明支持的平台运行真实的宿主语言测试和最小使用者测试。
- 验证打包、架构、加载、符号保留、取消和清理。
- 记录不支持的平台、未执行的测试以及受版本影响的假设。
资源
- 接口模型
- 脚手架代码与生成
- 语言绑定
- 异步、生命周期与回调
- 测试、打包与升级
- 内部机制与诊断
- 官方文档索引
- 执行场景
examples/golden-uniffi/:一个已编译的过程宏库,包含记录、枚举、对象、测试,以及版本锁定的本地 bindgen CLI。
数据隐私
未经授权,不要将专有 UDL、生成的绑定、原生库、符号、崩溃转储或宿主应用程序日志上传到外部服务。