🔗

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로 호출