Generate C-compatible FFI bindings from Rust crates for Python, Node, Swift, and Kotlin consumers.
Scanned 9/10/2026
Install to Claude Code
npx -y skills add LoopyLuci/Skills --skill rust-ffi-cross-language --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Rust Ffi Cross Language?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/loopyluci-rust-ffi-cross-language)More formats (shields.io, HTML) on the badges page.
---
name: rust-ffi-cross-language
description: 'Generate C-compatible FFI bindings from Rust crates for Python, Node, Swift, and Kotlin consumers.'
version: 1.0.0
author: Hermes Agent
license: MIT
platforms: [linux, macos, windows]
metadata:
hermes:
tags: ["rust", "ffi", "cbindgen", "bindgen", "interop"]
related_skills: ["rust-package-build", "rust-ownership-borrowing"]
---
Use when a Rust crate needs to be called from Python, Node.js, Swift, or Kotlin
without a separate FFI codegen step.
# Rust FFI Binding Generation
## Overview
cbindgen reads Rust `extern "C"` blocks and emits idiomatic C headers.
Pair with language-specific binders: `cffi` (Python), `node-ffi-napi` (Node),
a `.swift` wrapper (Swift), or `JNA` (Kotlin/Java).
## Procedure
1. `cargo add --build cbindgen` and add a `build.rs` that calls
`cbindgen::generate().write_to_file("mycrate.h")`.
2. Annotate every `#[no_mangle] extern "C"` function with `#[repr(C)]` and
use only POD-compatible types (ints, pointers, slices as `*const`/`*mut`).
3. For strings, pass `*const c_char` (null-terminated) or
`(*const u8, usize)` byte-slice pairs to avoid allocator coupling.
4. Build: `cargo build --release`. Distribute the `.so`/`.dylib`/`.dll`
alongside the generated header.
5. Language binders:
- Python: `ffi.cdef(open("mycrate.h").read()); lib = ffi.dlopen("libmycrate.so")`
- Node: define via `ffi-napi` using the same C signatures.
- Swift: `import Glibc` / `Darwin` and call through the `.so`.
6. Never cross an allocator boundary — Rust must allocate+deallocate (use a
`free` function exported the same way), or copy into a caller-owned buffer.
## Pitfalls
- Panics across the FFI boundary are UB; wrap entry points in
`std::panic::catch_unwinding`.
- `String`/`Vec` are NOT C-compatible — leak or segfault.
- Debug vs release ABIs differ; always ship release builds.
## Verification
- [ ] `cbindgen --config cbindgen.toml --crate mycrate --output mycrate.h` exits 0.
- [ ] `strings libmycrate.so | grep <exported_symbol>` shows the symbol.
- [ ] Python: `python3 -c "import mymod; print(mymod.add(2,3))"` prints 5.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!