Expand description
§prebindgen
A tool for separating the implementation of FFI interfaces from language-specific binding generation, allowing each to reside in different crates.
See also: prebindgen-proc-macro
for the procedural macros.
§Problem
When creating Rust libraries that need to expose FFI interfaces to multiple languages,
it may be preferable to create separate cdylib
or staticlib
crates for each language-specific binding.
This allows you to tailor each crate to the requirements and quirks of its binding generator and to specifisc of the
destination language.
However, #[no_mangle] extern "C"
functions can only be defined in a cdylib
or staticlib
crate, and cannot be
exported from a lib
crate. As a result, these functions must be duplicated in each language-specific
binding crate. This duplication is inconvenient for large projects with many FFI functions and types.
§Solution
prebindgen
solves this by generating #[no_mangle] extern "C"
Rust proxy source code from a common
Rust library crate.
Language-specific binding crates can then compile this generated code and pass it to their respective
binding generators (such as cbindgen, csbindgen, etc.).
§Usage example
See also example projects on https://github.com/milyin/prebindgen/tree/main/examples
See also the prebindgen-proc-macro documentation for details on how to use the #[prebindgen]
macro:
https://docs.rs/prebindgen-proc-macro/latest/prebindgen_proc_macro/
§1. In the Common FFI Library Crate (e.g., example_ffi
)
Mark structures and functions that are part of the FFI interface with the prebindgen
macro:
// example-ffi/src/lib.rs
use prebindgen_proc_macro::prebindgen;
// Export path to prebindgen output directory
const PREBINDGEN_OUT_DIR: &str = prebindgen_proc_macro::prebindgen_out_dir!();
// Export crate's features for verification
const FEATURES: &str = prebindgen_proc_macro::features!();
// Group structures and functions for selective handling
#[prebindgen]
#[repr(C)]
pub struct MyStruct {
pub field: i32,
}
#[prebindgen]
pub fn my_function(arg: i32) -> i32 {
arg * 2
}
Call init_prebindgen_out_dir
in the crate’s build.rs
:
// example-ffi/build.rs
prebindgen::init_prebindgen_out_dir();
§2. In Language-Specific FFI Binding Crate (named e.g. example-cbindgen
)
Add the common FFI library to build dependencies
# example-cbindgen/Cargo.toml
[dependencies]
example_ffi = { path = "../example_ffi" }
[build-dependencies]
example_ffi = { path = "../example_ffi" }
prebindgen = "0.2"
cbindgen = "0.24"
// example-cbindgen/build.rs
use prebindgen::{Source, batching::ffi_converter, collect::Destination};
use itertools::Itertools;
fn main() {
// Create a source from the common FFI crate's prebindgen data
let source = Source::new(example_ffi::PREBINDGEN_OUT_DIR);
// Process items with filtering and conversion
let destination = source
.items_all()
.batching(ffi_converter::Builder::new(source.crate_name())
.edition(prebindgen::Edition::Edition2024)
.strip_transparent_wrapper("std::mem::MaybeUninit")
.build()
.into_closure())
.collect::<Destination>();
// Write generated FFI code to file
let bindings_file = destination.write("ffi_bindings.rs");
// Pass the generated file to cbindgen for C header generation
generate_c_headers(&bindings_file);
}
Include the generated Rust files in your project to build the static or dynamic library itself:
// lib.rs
include!(concat!(env!("OUT_DIR"), "/ffi_bindings.rs"));
Modules§
- batching
- Filters for sequences of (syn::Item, SourceLocation) called by
itertools::batching
- collect
- Collectors for sequences of (syn::Item, SourceLocation) produced by
collect
- filter_
map - Filters for sequences of (syn::Item, SourceLocation) called by
filter_map
- map
- Filters for sequences of (syn::Item, SourceLocation) called by
map
- utils
Macros§
- trace
- Macro for debug tracing in build.rs. Used by prebindgen-proc-macro to display paths to generated files, but can be also used in other contexts.
Structs§
- Source
- Provides access to prebindgen data generated by the
#[prebindgen]
macro - Target
Triple - TargetTriple is a small utility around
target_lexicon::Triple
with helpers to access parts and to convert into Rust cfg tokens.
Enums§
- Rust
Edition - Rust edition for code generation
Constants§
- DEFAULT_
GROUP_ NAME - Default group name for items without explicit group name
Functions§
- get_
all_ features - Read all feature names declared in the current crate’s
Cargo.toml
. - get_
enabled_ features - Filter the full features list to only those that are currently enabled.
- get_
prebindgen_ out_ dir - Get the full path to the prebindgen output directory in OUT_DIR.
- init_
prebindgen_ out_ dir - Initialize the prebindgen output directory for the current crate
- is_
feature_ enabled - Check whether a feature is enabled by looking at the corresponding
CARGO_FEATURE_<NAME>
environment variable provided to build scripts by Cargo. Hyphens in feature names are converted to underscores to match Cargo’s env var format.