prebindgen/lib.rs
1//! # prebindgen
2//!
3//! A tool for separating the implementation of FFI interfaces from language-specific binding generation,
4//! allowing each to reside in different crates.
5//!
6//! See also: [`prebindgen-proc-macro`](https://docs.rs/prebindgen-proc-macro) for the procedural macros.
7//!
8//! ## Problem
9//!
10//! When creating Rust libraries that need to expose FFI interfaces to multiple languages,
11//! it may be preferable to create separate `cdylib` or `staticlib` crates for each language-specific binding.
12//! This allows you to tailor each crate to the requirements and quirks of its binding generator and to specifisc of the
13//! destination language.
14//! However, `#[no_mangle] extern "C"` functions can only be defined in a `cdylib` or `staticlib` crate, and cannot be
15//! exported from a `lib` crate. As a result, these functions must be duplicated in each language-specific
16//! binding crate. This duplication is inconvenient for large projects with many FFI functions and types.
17//!
18//! ## Solution
19//!
20//! `prebindgen` solves this by generating `#[no_mangle] extern "C"` Rust proxy source code from a common
21//! Rust library crate.
22//! Language-specific binding crates can then compile this generated code and pass it to their respective
23//! binding generators (such as cbindgen, csbindgen, etc.).
24//!
25//! ## Usage example
26//!
27//! See also example projects on <https://github.com/milyin/prebindgen/tree/main/examples>
28//!
29//! See also the prebindgen-proc-macro documentation for details on how to use the `#[prebindgen]` macro:
30//! <https://docs.rs/prebindgen-proc-macro/latest/prebindgen_proc_macro/>
31//!
32//! ### 1. In the Common FFI Library Crate (e.g., `example_ffi`)
33//!
34//! Mark structures and functions that are part of the FFI interface with the `prebindgen` macro:
35//!
36//! ```rust,ignore
37//! // example-ffi/src/lib.rs
38//! use prebindgen_proc_macro::prebindgen;
39//!
40//! // Export path to prebindgen output directory
41//! const PREBINDGEN_OUT_DIR: &str = prebindgen_proc_macro::prebindgen_out_dir!();
42//!
43//! // Export crate's features for verification
44//! const FEATURES: &str = prebindgen_proc_macro::features!();
45//!
46//! // Group structures and functions for selective handling
47//! #[prebindgen]
48//! #[repr(C)]
49//! pub struct MyStruct {
50//! pub field: i32,
51//! }
52//!
53//! #[prebindgen]
54//! pub fn my_function(arg: i32) -> i32 {
55//! arg * 2
56//! }
57//! ```
58//!
59//! Call [`init_prebindgen_out_dir`] in the crate's `build.rs`:
60//!
61//! ```rust,no_run
62//! // example-ffi/build.rs
63//! prebindgen::init_prebindgen_out_dir();
64//! ```
65//!
66//! ### 2. In Language-Specific FFI Binding Crate (named e.g. `example-cbindgen`)
67//!
68//! Add the common FFI library to build dependencies
69//!
70//! ```toml
71//! # example-cbindgen/Cargo.toml
72//! [dependencies]
73//! example_ffi = { path = "../example_ffi" }
74//!
75//! [build-dependencies]
76//! example_ffi = { path = "../example_ffi" }
77//! prebindgen = "0.2"
78//! cbindgen = "0.24"
79//! ```
80//! ```rust,ignore
81//! // example-cbindgen/build.rs
82//! use prebindgen::{Source, batching::ffi_converter, collect::Destination};
83//! use itertools::Itertools;
84//!
85//! fn main() {
86//! // Create a source from the common FFI crate's prebindgen data
87//! let source = Source::new(example_ffi::PREBINDGEN_OUT_DIR);
88//!
89//! // Process items with filtering and conversion
90//! let destination = source
91//! .items_all()
92//! .batching(ffi_converter::Builder::new(source.crate_name())
93//! .edition(prebindgen::Edition::Edition2024)
94//! .strip_transparent_wrapper("std::mem::MaybeUninit")
95//! .build()
96//! .into_closure())
97//! .collect::<Destination>();
98//!
99//! // Write generated FFI code to file
100//! let bindings_file = destination.write("ffi_bindings.rs");
101//!
102//! // Pass the generated file to cbindgen for C header generation
103//! generate_c_headers(&bindings_file);
104//! }
105//! ```
106//!
107//! Include the generated Rust files in your project to build the static or dynamic library itself:
108//!
109//! ```rust,ignore
110//! // lib.rs
111//! include!(concat!(env!("OUT_DIR"), "/ffi_bindings.rs"));
112//! ```
113//!
114
115/// File name for storing the crate name
116const CRATE_NAME_FILE: &str = "crate_name.txt";
117
118/// File name for storing enabled Cargo features collected in build.rs
119const FEATURES_FILE: &str = "features.txt";
120
121/// Default group name for items without explicit group name
122pub const DEFAULT_GROUP_NAME: &str = "default";
123
124pub(crate) mod api;
125pub(crate) mod codegen;
126
127pub use crate::api::{
128 buildrs::{
129 get_all_features, get_enabled_features, get_prebindgen_out_dir, init_prebindgen_out_dir,
130 is_feature_enabled,
131 },
132 record::SourceLocation,
133 source::Source,
134 utils::{edition::RustEdition, target_triple::TargetTriple},
135};
136
137/// Filters for sequences of (syn::Item, SourceLocation) called by `itertools::batching`
138pub mod batching {
139 pub mod ffi_converter {
140 pub use crate::api::batching::ffi_converter::Builder;
141 }
142 pub use crate::api::batching::{cfg_filter::CfgFilter, ffi_converter::FfiConverter};
143 pub mod cfg_filter {
144 pub use crate::api::batching::cfg_filter::Builder;
145 }
146}
147
148/// Filters for sequences of (syn::Item, SourceLocation) called by `filter_map`
149pub mod filter_map {
150 pub use crate::api::filter_map::struct_align::struct_align;
151}
152
153/// Filters for sequences of (syn::Item, SourceLocation) called by `map`
154pub mod map {
155 pub use crate::api::map::strip_derive::StripDerives;
156 pub mod strip_derive {
157 pub use crate::api::map::strip_derive::Builder;
158 }
159 pub use crate::api::map::strip_macro::StripMacros;
160 pub mod strip_macro {
161 pub use crate::api::map::strip_macro::Builder;
162 }
163 pub use crate::api::map::replace_types::ReplaceTypes;
164 pub mod replace_types {
165 pub use crate::api::map::replace_types::Builder;
166 }
167}
168
169/// Collectors for sequences of (syn::Item, SourceLocation) produced by `collect`
170pub mod collect {
171 pub use crate::api::collect::destination::Destination;
172}
173
174pub mod utils {
175 #[doc(hidden)]
176 pub use crate::api::utils::jsonl::{read_jsonl_file, write_to_jsonl_file};
177 pub use crate::api::utils::target_triple::TargetTriple;
178}
179
180#[doc(hidden)]
181pub use crate::api::record::Record;
182#[doc(hidden)]
183pub use crate::api::record::RecordKind;