rust-uniffi-building について
Rustライブラリを基盤に、Mozilla UniFFIのバインディングを設計、生成、統合、検証するスキルです。共有Rustロジックをホスト言語に公開する開発者向けに、バインディング、ネイティブ成果物、パッケージの契約全体を扱います。
主な機能
- 01UDLまたは手続きマクロを選択
- 02ホスト言語に適したAPIを設計
- 03対象言語向けバインディングを生成
- 04Rustとホスト言語のビルドを検証
- 05パッケージとネイティブ読み込みを確認
- 06バインディングや実行時の障害を診断
活用シーン
- 01RustライブラリのロジックをKotlinやSwiftに公開
- 02UniFFIバインディングを生成して統合
- 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 を構築します。「Swift と Android 向けにコアを一度だけ Rust で書く」「Kotlin と iOS から Rust を呼び出す」「モバイルとブラウザーのクライアント間で Rust のビジネスロジックを再利用する」といった依頼は、ユーザーが UniFFI という名前を挙げていなくても、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 の最小バージョン。
- ライブラリアーティファクトの種類、パッケージ名、名前空間/モジュール名、読み込みパス。
- エクスポートする関数、オブジェクト、レコード、列挙型、エラー、トレイト、コールバック、非同期呼び出し、カスタム型。
- スレッド処理、キャンセル、所有権、破棄、後方互換性に関する要件。
- 生成の担当箇所:Cargo ビルド、リポジトリにチェックインされたツール、Gradle/Xcode タスク、CI ジョブ、リリースパイプライン。
Cargo.lock と UniFFI の最新の公式ガイドを確認してください。別の UniFFI リリース系列の構文をコピーしないでください。リポジトリにあるゴールデン例は、ロックされているバージョンの根拠にはなりますが、普遍的な依存関係の推奨ではありません。
2. インターフェース定義戦略をひとつ選ぶ
| 戦略 | 適している場合 | 必要な対応 |
|---|---|---|
| 手続き型マクロ | Rust が API の唯一の信頼できる情報源であり、サポート対象の構成要素で契約を満たせる場合 | ライブラリモードを使用し、uniffi::setup_scaffolding!() を必ず一度だけ使用する |
| UDL | 言語に依存しない明示的なスキーマが必要な場合、または既存の UDL を引き続き正とする場合 | build.rs で生成し、生成されたスキャフォールディングをインクルードする |
| UDL とマクロの併用 | 移行中、または実際に未対応の構成要素が必要な場合 | UDL 単体で有効に保ち、クレート名を UDL の名前空間と一致させる |
ひとつのクレート内で uniffi::setup_scaffolding!() と uniffi::include_scaffolding!() の両方を呼び出してはいけません。利便性だけを理由に戦略を混在させないでください。重複定義や乖離のリスクが高まります。
公開型を設計する場合や、UDL とマクロのどちらを選ぶか決める場合は、インターフェースモデルを読んでください。
3. スキャフォールディングとアーティファクトの境界を確立する
手続き型マクロのみを使用するクレートでは、まず次の最小限のパターンから始めてください。
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"]
すべてのクレートタイプや UniFFI フィーチャーを自動的に有効化しないでください。ホスト側のパッケージング契約に基づいてアーティファクトを選択し、可能な場合は bindgen/CLI 依存関係を分離し、ランタイム向けの依存関係を最小限に保ってください。
UDL のビルドスクリプト、生成されたバインディング、設定の優先順位、ライブラリモードのコマンドについては、スキャフォールディングと生成を読んでください。
4. FFI 形式の公開 API を設計する
- UniFFI がサポートする型、または明示的なカスタム変換/外部変換のみをエクスポートします。
- 不変の値の受け渡しにはレコードを、ID や共有状態にはオブジェクトを優先します。
- 選択した UniFFI のバージョンで必要な場合は、エクスポートするオブジェクトのコンストラクターから
Arc<Self>を返します。 - 想定される失敗はエクスポートするエラー列挙型としてモデル化し、通常の失敗をパニックで表現しないでください。
- 内部の Rust 型は非公開にし、UniFFI 境界で変換します。
- 名前、フィールドの有無、列挙型のバリアント、デフォルト値、エラーバリアントは、ホスト言語との互換性に関わる重要な約束事として扱います。
- 文字列、バイトバッファー、コレクション、再帰構造、コールバックの頻度、応答サイズに上限を設けます。
- すべてのターゲット言語で扱いにくく、または安全でなくなる Rust 中心の API を公開しないでください。
futures、コールバック、トレイト、または状態を持つオブジェクトをエクスポートする前に、非同期処理、ライフタイム、コールバックをお読みください。
5. 言語ごとに生成して統合する
リリースするライブラリ/設定の組み合わせそのものからバインディングを生成します。生成されたソースとネイティブ成果物のバージョンを一致させてください。
生成されたファイルを確認するだけで終わらせず、言語ごとの統合を検証してください。
- Kotlin/Android:パッケージ/JNA またはプラットフォームブリッジ、Gradle タスクの入力、ABI 分割、コルーチンの動作、ネイティブライブラリの読み込み。
- Swift/Apple:Swift ソース、ヘッダー/モジュールマップ、静的または動的ライブラリのリンク、モジュール名、Xcode のビルドフェーズ、XCFramework のパッケージ化。
- Python:拡張機能/ライブラリの検出、生成されたモジュールのインポート、サポート対象の Python バージョン、wheel/プラットフォームのタグ付け。
- Ruby:生成されたラッパーの読み込み、選択したリリースについて文書化されている機能上の制限。
- WASM:不安定なサポートに関する制約、シングルスレッドの前提、JavaScript ツール、UniFFI のサポート対象機能。
依頼されたターゲット言語についてのみ、言語バインディングをお読みください。
6. 3 つの境界で検証する
まず 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 モード、クレート機能、最終ライブラリ成果物 |
| シンボルまたは定義が重複している | UDL とマクロの混在、スキャフォールディングの重複設定、複数の生成ソース |
| Bindgen がクレート/設定を見つけられない | cargo-metadata、グローバルな [crate-roots]、作業ディレクトリ、設定の優先順位 |
| 生成コードはコンパイルできるがライブラリを読み込めない | ファイル名、アーキテクチャ、ABI、検索パス、署名、パッケージ内容 |
| 値が破損する、またはデコードに失敗する | 型モデル、カスタムコンバーター、バージョンの不一致、lowering/lifting の契約 |
| オブジェクトが消える、リークする、または競合する | 参照カウント、ホスト側のライフタイム、コールバック登録、スレッドポリシー |
| 非同期処理が停止する、またはキャンセル時に作業が残る | ランタイム機能、外部エグゼキューター/ポーラー、キャンセルと完了の契約 |
| リリースビルドでのみ失敗する | デッドストリッピング、LTO、シンボル保持、機能/プロファイルの違い |
表面的な確認では失敗の原因を説明できない場合に限り、内部実装と診断をお読みください。
注意点
- UniFFI はバインディングを生成しますが、すべてのプラットフォーム向けにネイティブライブラリを同梱、署名、公開、読み込みするわけではありません。
- 生成されたバインディングと Rust アーティファクトは、互換性のある UniFFI メタデータと設定に基づいている必要があります。
latestのドキュメントは更新される可能性があります。クレートのバージョンを固定し、リリース判断に使用したガイドのスナップショットを記録してください。- UDL ファイルは、マクロがサポート対象の項目を追加する場合でも、完全なスキーマとして扱われます。
- 必要に応じて、エクスポート対象の impl ブロックを分けて
#[cfg]を付けてください。エクスポート対象ブロック内の条件付き項目も、互換性のないスキャフォールディングを生成する場合があります。 - ホスト言語の命名、例外、null 許容性、コレクション、ライフサイクルのセマンティクスは、Rust のセマンティクスと同一ではありません。
- Miri では実際の外部ランタイムを検証できません。Rust 側の unsafe コードには Miri を使用し、その後、プラットフォーム統合テストを実行してください。
使用しない場合
次の場合、このスキルを有効にしないでください。
- 外部言語のコンシューマーを持たない、通常の Rust ライブラリ API の場合。
- タスクで UniFFI の採用または比較が明示的に求められていない限り、
wasm-bindgen、CXX、PyO3、JNI、cbindgen、Diplomat、または生の C バインディングを扱う場合。 - UniFFI に関係しない汎用の derive マクロや attribute マクロを作成する場合。
- UniFFI のコントラクト、コード、アーティファクトに変更がない状態で、すでに生成済みのバインディングをパッケージ化する場合。
完了基準
- バージョン、ターゲット、言語、生成担当者、アーティファクト/パッケージのコントラクトを固定します。
- 重複したスキャフォールディングが生じないように、手続き型マクロ、UDL、または根拠のある混合方式を選択します。
- エクスポート対象の型、エラー、所有権、コールバック、非同期処理、互換性のモデルを明確にします。
- 実際に出荷するライブラリと設定からバインディングを生成します。
- Rust の検証に加え、対象とするすべてのプラットフォームで、実際のホスト言語と最小コンシューマーのテストを実行します。
- パッケージ化、アーキテクチャ、読み込み、シンボルの保持、キャンセル、クリーンアップを検証します。
- サポート対象外のプラットフォーム、未実行のテスト、バージョンに依存する前提を記録します。
リソース
- インターフェースモデル
- スキャフォールディングと生成
- 言語バインディング
- 非同期処理、ライフタイム、コールバック
- テスト、パッケージ化、アップグレード
- 内部構造と診断
- 公式ドキュメントの一覧
- 実行シナリオ
examples/golden-uniffi/:レコード、列挙型、オブジェクト、テスト、およびバージョンを固定したローカルの bindgen CLI を含む、コンパイル済みの手続き型マクロライブラリです。
データのプライバシー
許可なく、独自仕様の UDL、生成されたバインディング、ネイティブライブラリ、シンボル、クラッシュダンプ、またはホストアプリケーションのログを外部サービスにアップロードしないでください。