🔗
FFI — Rust에서 C 라이브러리 호출하기
extern "C", bindgen, unsafe의 실전 사용법
Rust 생태계가 아무리 커도 C/C++로 된 기존 라이브러리를 다 대체할 수는 없다. SQLite, OpenSSL, libcurl — 이런 건 Rust에서 직접 호출해야 한다.
extern "C" {
fn strlen(s: *const c_char) -> usize;
}
let len = unsafe { strlen(c_str.as_ptr()) };
unsafe가 필요한 이유: C 함수는 Rust의 소유권/빌림 규칙을 따르지 않는다. 널 포인터를 넘기면 세그폴트가 나고, 메모리 해제를 잘못하면 double free가 난다. Rust 컴파일러가 보장할 수 없는 영역이라 프로그래머가 책임진다.
bindgen — C 헤더 파일(.h)을 읽어서 Rust 바인딩 코드를 자동 생성한다. 수백 개 함수를 수동으로 선언할 필요 없다.
역방향(Rust를 C에서 호출): #[no_mangle] pub extern "C" fn — VOICEVOX Core가 정확히 이 패턴으로 Python Engine에 C ABI를 노출한다.
핵심 포인트
1
extern "C" 블록에 C 함수 시그니처 선언
2
build.rs에서 C 라이브러리를 링크 (println!("cargo:rustc-link-lib=..."))
3
unsafe 블록에서 C 함수 호출 — 안전성은 프로그래머가 보장
4
안전한 Rust 래퍼 함수로 감싸서 사용자에게 safe API 제공
장점
- ✓ C/C++ 생태계의 모든 라이브러리를 Rust에서 사용 가능
- ✓ unsafe를 래퍼로 감싸면 나머지 코드는 안전
단점
- ✗ unsafe 코드의 안전성은 프로그래머 책임
- ✗ C 라이브러리의 빌드 설정이 플랫폼별로 복잡
사용 사례
rusqlite — SQLite C 라이브러리의 Rust 바인딩
VOICEVOX Core — Rust를 C ABI로 노출, Python에서 ctypes로 호출