Week 14 - FFI: Calling C, Being Called By C¶
14.1 Conceptual Core¶
- The C ABI is the lingua franca. Rust can both consume it (
extern "C" fndeclarations) and expose it (#[no_mangle] pub extern "C" fn). - Two directions of pain:
- Calling C from Rust-bindings, header parsing (bindgen), null-pointer discipline,
CStr/CStringlifetimes, errno. - Calling Rust from C-symbol mangling, panic discipline (panics across FFI = UB), opaque pointers, version-stable headers (cbindgen).
14.2 Mechanical Detail¶
bindgen: parses C headers via libclang, emits Rustexterndeclarations. Configure viawrapper.handbuild.rs. Common pitfalls: bitfield representation, function-like macros (not handled), inline functions (must be static-libbed separately).cbindgen: the inverse. Reads your Rust source and emits a C header. Requires acbindgen.toml. Generated headers should be checked intoinclude/and CI-verified.#[repr(C)]is mandatory for any type crossing the boundary.#[repr(transparent)]for newtype wrappers around FFI primitives.- Strings:
CStris unsized borrowed,CStringis owned. Never assume a*const c_charis UTF-8-convert throughCStr::from_ptrand thento_str(). - Panic safety across FFI: panics that unwind across an
extern "C"boundary are UB. Wrap everyextern "C" fnbody instd::panic::catch_unwindand convert panics to error codes, or compile withpanic = "abort". - errno: thread-local in glibc; access via
std::io::Error::last_os_error()immediately after a syscall.
14.3 Lab-"Bind a Real C Library and Expose a Rust One"¶
Two parts:
1. Consume: write Rust bindings to libsodium's crypto_secretbox family. Use bindgen for the raw layer, then wrap in safe Rust (own the keys with Zeroizing<[u8; 32]>, use typed nonces, return Results).
2. Expose: take your parse-units crate from Month 1 and ship a C-callable parse_units_c library with a cbindgen - generated header. Provide aMakefile` that links a tiny C program against it.
14.4 Idiomatic & Clippy Drill¶
clippy::not_unsafe_ptr_arg_deref,clippy::missing_safety_doc,clippy::fn_to_numeric_cast_any,clippy::transmute_ptr_to_ptr. The first two are FFI-specific safety doc enforcers.
14.5 Production Hardening Slice¶
- Cross-compile your
parse-unitsC library toaarch64-unknown-linux-gnuandx86_64-unknown-linux-musl. Verify the resulting.so/.aartifacts withnmandreadelf. Add this to CI as a matrix build.