llama_cpp_sys/lib.rs
1//! Raw FFI bindings to [llama.cpp](https://github.com/ggml-org/llama.cpp),
2//! plus the first-party C++ shim (`wrapper.cpp`) that exposes the `_c`-suffixed
3//! symbols our Rust callers consume.
4//!
5//! # Activation
6//!
7//! The real bindings are hidden behind the `bindings` cargo feature. A default
8//! build (`cargo build -p llama-cpp-sys`) compiles this crate to an empty
9//! shell on every target — this keeps the workspace-wide `cargo clippy` /
10//! `cargo check` on Linux CI runners green, because llama.cpp's cmake build
11//! requires a C++ toolchain and pulls in ~180 MB of source.
12//!
13//! To get the actual FFI surface, build with `--features bindings`. The
14//! build script will use the in-tree `vendor/llama-cpp` directory if
15//! present, and otherwise clone the pinned commit
16//! `b46812de78f8fbcb6cf0154947e8633ebc78d9ac` from GitHub into `$OUT_DIR`.
17//!
18//! # Safety and stability
19//!
20//! This is a `-sys` crate: every item under [`bindings`] is `unsafe extern "C"`
21//! and mirrors the upstream C ABI (after the `_c` suffix introduced by
22//! `wrapper.cpp`) one-to-one. It is not meant to be consumed directly outside
23//! the workspace. The safe wrapper crate `xybrid-llama` owns the RAII, typed
24//! error mapping, and streaming-trampoline concerns.
25//!
26//! The generated bindings are intentionally *not* re-exported transitively:
27//! downstream crates opt in explicitly by depending on `llama-cpp-sys` with
28//! the `bindings` feature and using the items behind [`bindings`].
29//!
30//! # Phase note (epic: `llamacpp-crate-split`)
31//!
32//! The extern declarations in [`bindings`] are generated by bindgen from
33//! `wrapper.h`, which declares the first-party `_c` shim surface consumed by
34//! `xybrid-llama`.
35
36#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
37
38#[cfg(feature = "bindings")]
39pub mod bindings {
40 //! Generated FFI bindings emitted by `bindgen` against [`wrapper.h`].
41 //!
42 //! Phase 5 of the `llamacpp-crate-split` epic — replaces the
43 //! prior 26-symbol hand-written `extern "C" {}` block. Bindgen
44 //! processes `wrapper.h` (which both #includes `<llama.h>` and
45 //! declares the first-party `_c` shim functions) and emits one
46 //! generated `bindings.rs` file consumed via `include!` below.
47 //!
48 //! The allowlist in `build.rs` keeps the surface focused on
49 //! `llama_.*` (functions, types, and `LLAMA_.*` constants);
50 //! `ggml_.*` is intentionally NOT allowlisted because no
51 //! `xybrid-llama` / `xybrid-core` consumer references a `ggml_*`
52 //! symbol directly — wrapper.cpp handles all ggml interop.
53 //!
54 //! See `.notes/bindgen-symbol-diff.md` for the symbol-by-symbol
55 //! diff against the pre-Phase-5 hand-written list.
56
57 // Mirror `mlx-c-sys::bindings`'s lint allowances. Bindgen output
58 // routinely trips dead_code, improper_ctypes, and the broader
59 // clippy lints; the wide allowances keep the generated module
60 // lint-free without needing to post-process bindings.rs.
61 #![allow(
62 non_camel_case_types,
63 non_snake_case,
64 non_upper_case_globals,
65 dead_code,
66 improper_ctypes,
67 clippy::all,
68 clippy::pedantic,
69 clippy::nursery,
70 clippy::cargo
71 )]
72
73 use std::os::raw::{c_char, c_int, c_void};
74
75 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
76
77 /// Convenience alias for the bindgen-generated streaming callback
78 /// typedef. Bindgen emits `llama_token_callback_c` as
79 /// `Option<unsafe extern "C" fn(...)>` (Option already wrapping the
80 /// function pointer); `TokenCallback` here is the inner `unsafe
81 /// extern "C" fn(...)` so `xybrid-llama` can construct
82 /// `Some(streaming_trampoline::<F>)` against an
83 /// `Option<TokenCallback>`-shaped FFI argument.
84 pub type TokenCallback = unsafe extern "C" fn(
85 token_id: c_int,
86 token_text: *const c_char,
87 user_data: *mut c_void,
88 ) -> c_int;
89}
90
91/// Initialize the llama.cpp backend. Idempotent across calls thanks to the
92/// internal [`std::sync::Once`] guard, so safe to invoke from every
93/// backend-construction call site — only the first invocation actually runs
94/// `llama_backend_init_c()`.
95///
96/// We intentionally never call `llama_backend_free_c()`. The `Once` guard
97/// cannot be re-armed, so if we freed the backend when the last instance
98/// drops and then created a new instance (e.g., during model swap), the
99/// backend would NOT be re-initialized — causing undefined behavior. Since
100/// `llama_backend_free_c()` only cleans up NUMA info (a no-op on most
101/// platforms), skipping it is safe. The OS reclaims all resources at
102/// process exit.
103///
104/// This `-sys` crate deliberately does not read Xybrid-specific environment
105/// variables. Higher-level crates that need policy during backend startup
106/// should call [`backend_init_with_configure`] and keep their configuration
107/// hook in the same one-time init closure.
108#[cfg(feature = "bindings")]
109pub fn backend_init() {
110 backend_init_with_configure(|| {});
111}
112
113/// Initialize the llama.cpp backend once, running `configure` immediately
114/// after `llama_backend_init_c()` during the same one-time initialization.
115///
116/// This preserves the historical timing for higher-level policies such as
117/// log-verbosity setup while keeping this `-sys` crate free of product-level
118/// environment-variable contracts.
119#[cfg(feature = "bindings")]
120pub fn backend_init_with_configure(configure: impl FnOnce()) {
121 use std::sync::Once;
122 static BACKEND_INIT: Once = Once::new();
123 BACKEND_INIT.call_once(|| {
124 unsafe { bindings::llama_backend_init_c() };
125 configure();
126 });
127}
128
129/// No-op stub when the `bindings` feature is disabled. Lets the wrapper
130/// crate's `LlamaCppBackend::new()` constructor call `backend_init()`
131/// unconditionally without a `#[cfg]` branch.
132#[cfg(not(feature = "bindings"))]
133pub fn backend_init() {}
134
135/// No-op stub when the `bindings` feature is disabled.
136#[cfg(not(feature = "bindings"))]
137pub fn backend_init_with_configure(_configure: impl FnOnce()) {}