К основному содержанию
скилл CX Codex

rust-ffi — скилл для Claude Code: вызов C из Rust и обратно

Ведёт агента по FFI между Rust и C: генерация биндингов через bindgen и cbindgen, безопасные обёртки, линковка системных библиотек.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add mohitmishra786/low-level-dev-skills --skill rust-ffi -a claude-code
Открыть на GitHub

Что делает rust-ffi

Скилл описывает шесть шагов работы с Foreign Function Interface. Сначала ручные объявления extern "C", потом автоматическая генерация биндингов через bindgen с настройками allowlist_function, derive_debug и blocklist_type для проблемных типов. Дальше — структура sys-крейта: отдельный mylib-sys с links = "mylib" и build.rs, который сначала пробует pkg-config, а при неудаче собирает вендорный исходник через cc::Build.

Отдельные разделы про безопасные обёртки и экспорт Rust в C. Обёртка прячет сырой указатель за структурой с Drop, реализует Send и Sync там, где это оправдано, и превращает коды возврата C в Result. Для экспорта используются #[no_mangle], extern "C" и Box::into_raw с обратным Box::from_raw при уничтожении. cbindgen генерирует заголовок include/mylib.h из build.rs.

Для сборки нужен clang: bindgen разбирает заголовки через clang_arg, и без него шаг с генерацией биндингов не пройдёт. Линковка описана для статических и динамических библиотек, а также фреймворков macOS вроде CoreFoundation. Есть ссылка на references/bindgen-cbindgen.md с деталями конфигурации.

Какие задачи решает

  • вызвать функцию из C-библиотеки в Rust без ручного переписывания заголовков
  • сгенерировать Rust-биндинги из wrapper.h через bindgen
  • экспортировать Rust-функции наружу и получить C-заголовок через cbindgen
  • обернуть небезопасный C API в тип с автоматическим освобождением ресурсов
  • собрать sys-крейт с build.rs и линковкой системной библиотеки

Примеры запросов агенту

  • Помоги сгенерировать биндинги для wrapper.h через bindgen в build.rs
  • Как обернуть этот C API в безопасный тип с Drop?
  • Настрой cbindgen, чтобы он писал заголовок в include/mylib.h

Как установить rust-ffi

1Через Skills CLI (Vercel)

npx skills add mohitmishra786/low-level-dev-skills --skill rust-ffi -a claude-code

2Вручную: положить файлы

~/.claude/skills/rust-ffi/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/rust-ffi/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о rust-ffi

Как установить rust-ffi в Claude?

Выполните npx skills add mohitmishra786/low-level-dev-skills --skill rust-ffi -a claude-code. Скилл окажется в ~/.claude/skills/rust-ffi/SKILL.md.

Что делает rust-ffi?

Проводит агента по шагам FFI: ручные объявления extern "C", генерация биндингов, структура sys-крейта, безопасные обёртки, экспорт Rust в C и линковка библиотек в build.rs.

Что нужно для генерации биндингов?

bindgen разбирает заголовки через clang, поэтому clang должен быть доступен в системе. В build.rs путь к заголовкам задаётся через clang_arg.

Исходный текст

SKILL.md · MIT
---
name: rust-ffi
description: Rust FFI skill for C interoperability. Use when calling C libraries from Rust, generating Rust bindings with bindgen, exporting Rust functions to C with cbindgen, writing safe wrappers around unsafe FFI, or linking system and vendor libraries. Activates on queries about bindgen, cbindgen, extern "C", unsafe FFI, Rust C bindings, linking C from Rust, or sys crates.
---

# Rust FFI

## Purpose

Guide agents through Rust's Foreign Function Interface: calling C from Rust with bindgen, exporting Rust to C with cbindgen, writing safe wrappers, linking libraries via `build.rs`, and structuring sys crates.

## Triggers

- "How do I call a C library from Rust?"
- "How do I use bindgen to generate Rust bindings?"
- "How do I export Rust functions to be called from C?"
- "How do I write a safe wrapper around an unsafe C API?"
- "How do I link a system library in Rust?"
- "What is a sys crate and how do I structure one?"

## Workflow

### 1. Calling C without bindgen (manual declarations)

```rust
// Declare external C functions manually
use std::ffi::{c_int, c_char, c_void, CStr, CString};

extern "C" {
    fn strlen(s: *const c_char) -> usize;
    fn malloc(size: usize) -> *mut c_void;
    fn free(ptr: *mut c_void);
    fn my_lib_init(config: *const c_char) -> c_int;
    fn my_lib_process(handle: *mut c_void, data: *const u8, len: usize) -> c_int;
    fn my_lib_cleanup(handle: *mut c_void);
}

// Call unsafe C function safely
fn init(config: &str) -> Result<*mut c_void, Error> {
    let c_config = CString::new(config)?;
    let result = unsafe { my_lib_init(c_config.as_ptr()) };
    if result != 0 {
        return Err(Error::InitFailed(result));
    }
    // return handle...
    todo!()
}
```

### 2. bindgen for automatic binding generation

```toml
# Cargo.toml
[build-dependencies]
bindgen = "0.70"
```

```rust
// build.rs
use std::path::PathBuf;

fn main() {
    println!("cargo:rerun-if-changed=wrapper.h");
    println!("cargo:rustc-link-lib=mylib");
    println!("cargo:rustc-link-search=/usr/local/lib");

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .clang_arg("-I/usr/local/include")
        .clang_arg("-DMYLIB_VERSION=2")
        // Only generate bindings for this library (not system headers)
        .allowlist_function("mylib_.*")
        .allowlist_type("MyLib.*")
        .allowlist_var("MYLIB_.*")
        // Derive common traits on structs
        .derive_debug(true)
        .derive_default(true)
        // Block problematic types
        .blocklist_type("__va_list_tag")
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
```

```rust
// src/lib.rs — include generated bindings
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
```

### 3. sys crate pattern

Structure:
```
mylib-sys/
├── Cargo.toml
├── build.rs        # links the library
├── wrapper.h       # C headers to translate
└── src/
    └── lib.rs      # includes generated bindings

mylib/             # safe wrapper
├── Cargo.toml
└── src/
    └── lib.rs
```

```toml
# mylib-sys/Cargo.toml
[package]
name = "mylib-sys"
version = "0.1.0"
links = "mylib"          # tells Cargo this crate links libmylib

[build-dependencies]
bindgen = "0.70"
pkg-config = "0.3"       # for system library detection
```

```rust
// mylib-sys/build.rs
fn main() {
    // Try pkg-config first
    if let Ok(lib) = pkg_config::probe_library("mylib") {
        for path in lib.include_paths {
            println!("cargo:include={}", path.display());
        }
        return;
    }

    // Fallback: compile from vendored source
    cc::Build::new()
        .file("vendor/mylib/src/mylib.c")
        .include("vendor/mylib/include")
        .compile("mylib");

    println!("cargo:rerun-if-changed=vendor/mylib/src/mylib.c");
}
```

### 4. Writing safe wrappers

```rust
// mylib/src/lib.rs
use mylib_sys as ffi;
use std::ffi::{CStr, CString};

pub struct MyLib {
    handle: *mut ffi::mylib_t,
}

// Safety: handle is not shared across threads
unsafe impl Send for MyLib {}
unsafe impl Sync for MyLib {}

impl MyLib {
    pub fn new(config: &str) -> Result<Self, Error> {
        let c_config = CString::new(config).map_err(|_| Error::InvalidConfig)?;
        let handle = unsafe { ffi::mylib_create(c_config.as_ptr()) };
        if handle.is_null() {
            return Err(Error::InitFailed);
        }
        Ok(Self { handle })
    }

    pub fn process(&mut self, data: &[u8]) -> Result<usize, Error> {
        let result = unsafe {
            ffi::mylib_process(self.handle, data.as_ptr(), data.len())
        };
        if result < 0 {
            return Err(Error::ProcessFailed(result));
        }
        Ok(result as usize)
    }
}

impl Drop for MyLib {
    fn drop(&mut self) {
        unsafe { ffi::mylib_destroy(self.handle) };
    }
}
```

### 5. Exporting Rust to C with cbindgen

```toml
# Cargo.toml
[build-dependencies]
cbindgen = "0.27"
```

```rust
// src/lib.rs — exported Rust API
#[no_mangle]
pub extern "C" fn mylib_create(config: *const std::ffi::c_char) -> *mut MyLib {
    // ...
    Box::into_raw(Box::new(instance))
}

#[no_mangle]
pub extern "C" fn mylib_destroy(ptr: *mut MyLib) {
    if !ptr.is_null() {
        unsafe { drop(Box::from_raw(ptr)) };
    }
}

#[no_mangle]
pub extern "C" fn mylib_process(
    ptr: *mut MyLib,
    data: *const u8,
    len: usize,
) -> std::ffi::c_int {
    let lib = unsafe { &mut *ptr };
    match lib.process(unsafe { std::slice::from_raw_parts(data, len) }) {
        Ok(n) => n as std::ffi::c_int,
        Err(_) => -1,
    }
}
```

```rust
// build.rs
fn main() {
    let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    cbindgen::Builder::new()
        .with_crate(crate_dir)
        .with_language(cbindgen::Language::C)
        .generate()
        .expect("Unable to generate C bindings")
        .write_to_file("include/mylib.h");
}
```

### 6. Linking libraries in build.rs

```rust
// build.rs — common patterns
fn main() {
    // Static library
    println!("cargo:rustc-link-lib=static=mylib");
    println!("cargo:rustc-link-search=native=/path/to/lib");

    // Dynamic library
    println!("cargo:rustc-link-lib=dylib=mylib");

    // Framework (macOS)
    println!("cargo:rustc-link-lib=framework=CoreFoundation");

    // Build C source with cc crate
    cc::Build::new()
        .file("src/helper.c")
        .flag("-std=c11")
        .compile("helper");
}
```

For bindgen and cbindgen configuration details, see [references/bindgen-cbindgen.md](references/bindgen-cbindgen.md).

## Related skills

- Use `skills/rust/rustc-basics` for RUSTFLAGS affecting FFI builds
- Use `skills/rust/cargo-workflows` for build.rs integration and sys crate layout
- Use `skills/zig/zig-cinterop` for Zig's equivalent C interop approach
- Use `skills/binaries/dynamic-linking` for dynamic library linking details

© mohitmishra786 · MIT · mohitmishra786/low-level-dev-skills

Похожие скиллы

Все скиллы по теме «Языки программирования» →
rust-pro Seth Hobson Субагент на модели Opus для разработки на Rust 1.75+. Помогает писать асинхронный код на Tokio и axum, настраивать многопоточность и разбираться с проверками заимствований. CX Codex 1 148установок dart-setup-ffi-assets flutter Скилл помогает агентам автоматизировать компиляцию и упаковку кода на C/C++ в динамические или статические библиотеки через систему Native Assets в Dart. Нужен, если вы интегрируете нативный код в Flutter или Dart-пакеты. CX Codex +1 14 000установок rust-async-patterns Seth Hobson Скилл помогает писать и разбирать асинхронный Rust на Tokio: задачи, каналы, потоки и обработку ошибок. Пригодится для сетевых сервисов и отладки. CX Codex 20 625установок rust-mcp-server-generator официальный github Скилл создаёт проект MCP-сервера на Rust с инструментами, промптами, ресурсами и тестом. Подойдёт, если вы хотите начать сервер с заданной структуры и официальным SDK rmcp. 9 181установок rust-engineer https://github.com/Jeffallan Направляет агента писать и проверять идиоматичный код на Rust 2021. Помогает настроить времена жизни, связать трейты и развернуть асинхронный сервис на tokio. CX Codex +1 6 300установок rust-patterns affaan-m Задаёт правила идиоматичного Rust: управление владением, типизированные ошибки, сопоставление с образцом и трейты. Пригодится при написании, рефакторинге и ревью Rust-кода. CX Codex +1 5 100установок

Из того же набора62

binutils Скилл для работы с бинарниками: статические библиотеки, strip, objcopy, addr2line, strings и c++filt. Пригодится, когда агент должен сам разобраться с постобработкой ELF. CX Codex +1 608установок dynamic-linking Скилл для работы с динамической линковкой в Linux: разбирает ошибки загрузки .so, настройку RPATH и RUNPATH, версионирование soname. CX Codex +1 600установок rust-profiling Скилл для анализа производительности Rust: флеймграфы, размер бинарника, раздувание мономорфизации и микробенчмарки Criterion. CX Codex +1 586установок interpreters Подсказывает агенту, как устроить диспетчеризацию байткода, стековую или регистровую ВМ и простой JIT через mmap. CX Codex +1 564установок meson Скилл для ИИ-агентов, который помогает настроить Meson, разобраться с wrap-зависимостями и кросс-компиляцией в C/C++ проектах. CX Codex +1 560установок cargo-workflows Скилл ведёт агента по воркспейсам Cargo, фичам, build.rs, кэшу сборки и аудиту зависимостей. Пригодится, когда Rust-проект разрастается до нескольких крейтов. CX Codex +1 558установок cpp-modules Скилл для работы с модулями C++20: именованные модули, партиции, header units, сборка через CMake и флаги компиляторов. CX Codex +1 555установок rust-security Скилл для проверки Rust-проектов на уязвимости: cargo-audit, cargo-deny, RUSTSEC, безопасный FFI, фаззинг и Miri. CX Codex +1 544установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой