1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//! # 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`](https://docs.rs/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:
//!
//! ```rust,ignore
//! // 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`:
//!
//! ```rust,no_run
//! // 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
//!
//! ```toml
//! # example-cbindgen/Cargo.toml
//! [dependencies]
//! example_ffi = { path = "../example_ffi" }
//!
//! [build-dependencies]
//! example_ffi = { path = "../example_ffi" }
//! prebindgen = "0.2"
//! cbindgen = "0.24"
//! ```
//! ```rust,ignore
//! // 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:
//!
//! ```rust,ignore
//! // lib.rs
//! include!(concat!(env!("OUT_DIR"), "/ffi_bindings.rs"));
//! ```
//!
/// File name for storing the crate name
const CRATE_NAME_FILE: &str = "crate_name.txt";
/// File name for storing enabled Cargo features collected in build.rs
const FEATURES_FILE: &str = "features.txt";
/// Default group name for items without explicit group name
pub const DEFAULT_GROUP_NAME: &str = "default";
pub
pub
pub use crate;
/// Filters for sequences of (syn::Item, SourceLocation) called by `itertools::batching`
/// Filters for sequences of (syn::Item, SourceLocation) called by `filter_map`
/// Filters for sequences of (syn::Item, SourceLocation) called by `map`
/// Collectors for sequences of (syn::Item, SourceLocation) produced by `collect`
pub use crateRecord;
pub use crateRecordKind;