summaryrefslogtreecommitdiff
path: root/bindgen
diff options
context:
space:
mode:
Diffstat (limited to 'bindgen')
-rw-r--r--bindgen/Cargo.toml1
-rw-r--r--bindgen/codegen/mod.rs108
-rw-r--r--bindgen/codegen/serialize.rs356
-rw-r--r--bindgen/ir/context.rs16
-rw-r--r--bindgen/ir/function.rs31
-rw-r--r--bindgen/lib.rs120
6 files changed, 567 insertions, 65 deletions
diff --git a/bindgen/Cargo.toml b/bindgen/Cargo.toml
index 2292a5ef..6d4902d4 100644
--- a/bindgen/Cargo.toml
+++ b/bindgen/Cargo.toml
@@ -48,6 +48,7 @@ runtime = ["clang-sys/runtime"]
# Dynamically discover a `rustfmt` binary using the `which` crate
which-rustfmt = ["which"]
cli = []
+experimental = []
# These features only exist for CI testing -- don't use them if you're not hacking
# on bindgen!
diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs
index 6b24ae1b..b6fb70eb 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -4,6 +4,7 @@ mod helpers;
mod impl_debug;
mod impl_partialeq;
mod postprocessing;
+mod serialize;
pub mod struct_layout;
#[cfg(test)]
@@ -59,6 +60,29 @@ use std::iter;
use std::ops;
use std::str::FromStr;
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum CodegenError {
+ Serialize { msg: String, loc: String },
+ Io(String),
+}
+
+impl From<std::io::Error> for CodegenError {
+ fn from(err: std::io::Error) -> Self {
+ Self::Io(err.to_string())
+ }
+}
+
+impl std::fmt::Display for CodegenError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CodegenError::Serialize { msg, loc } => {
+ write!(f, "serialization error at {}: {}", loc, msg)
+ }
+ CodegenError::Io(err) => err.fmt(f),
+ }
+ }
+}
+
// Name of type defined in constified enum module
pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type";
@@ -241,6 +265,8 @@ struct CodegenResult<'a> {
/// function name to the number of overloads we have already codegen'd for
/// that name. This lets us give each overload a unique suffix.
overload_counters: HashMap<String, u32>,
+
+ items_to_serialize: Vec<ItemId>,
}
impl<'a> CodegenResult<'a> {
@@ -258,6 +284,7 @@ impl<'a> CodegenResult<'a> {
functions_seen: Default::default(),
vars_seen: Default::default(),
overload_counters: Default::default(),
+ items_to_serialize: Default::default(),
}
}
@@ -4000,11 +4027,16 @@ impl CodeGenerator for Function {
debug!("<Function as CodeGenerator>::codegen: item = {:?}", item);
debug_assert!(item.is_enabled_for_codegen(ctx));
- // We can't currently do anything with Internal functions so just
- // avoid generating anything for them.
- match self.linkage() {
- Linkage::Internal => return None,
- Linkage::External => {}
+ let is_internal = matches!(self.linkage(), Linkage::Internal);
+
+ if is_internal {
+ if ctx.options().wrap_static_fns {
+ result.items_to_serialize.push(item.id());
+ } else {
+ // We can't do anything with Internal functions if we are not wrapping them so just
+ // avoid generating anything for them.
+ return None;
+ }
}
// Pure virtual methods have no actual symbol, so we can't generate
@@ -4114,6 +4146,7 @@ impl CodeGenerator for Function {
write!(&mut canonical_name, "{}", times_seen).unwrap();
}
+ let mut has_link_name_attr = false;
let link_name = mangled_name.unwrap_or(name);
if !is_dynamic_function &&
!utils::names_will_be_identical_after_mangling(
@@ -4123,6 +4156,7 @@ impl CodeGenerator for Function {
)
{
attributes.push(attributes::link_name(link_name));
+ has_link_name_attr = true;
}
// Unfortunately this can't piggyback on the `attributes` list because
@@ -4133,6 +4167,11 @@ impl CodeGenerator for Function {
quote! { #[link(wasm_import_module = #name)] }
});
+ if is_internal && ctx.options().wrap_static_fns && !has_link_name_attr {
+ let name = canonical_name.clone() + ctx.wrap_static_fns_suffix();
+ attributes.push(attributes::link_name(&name));
+ }
+
let ident = ctx.rust_ident(canonical_name);
let tokens = quote! {
#wasm_link_attribute
@@ -4437,7 +4476,8 @@ impl CodeGenerator for ObjCInterface {
pub(crate) fn codegen(
context: BindgenContext,
-) -> (proc_macro2::TokenStream, BindgenOptions, Vec<String>) {
+) -> Result<(proc_macro2::TokenStream, BindgenOptions, Vec<String>), CodegenError>
+{
context.gen(|context| {
let _t = context.timer("codegen");
let counter = Cell::new(0);
@@ -4487,21 +4527,73 @@ pub(crate) fn codegen(
result.push(dynamic_items_tokens);
}
- postprocessing::postprocessing(result.items, context.options())
+ utils::serialize_items(&result, context)?;
+
+ Ok(postprocessing::postprocessing(
+ result.items,
+ context.options(),
+ ))
})
}
pub mod utils {
- use super::{error, ToRustTyOrOpaque};
+ use super::serialize::CSerialize;
+ use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
use crate::ir::context::BindgenContext;
use crate::ir::function::{Abi, ClangAbi, FunctionSig};
use crate::ir::item::{Item, ItemCanonicalPath};
use crate::ir::ty::TypeKind;
+ use crate::{args_are_cpp, file_is_cpp};
use proc_macro2;
use std::borrow::Cow;
use std::mem;
+ use std::path::PathBuf;
use std::str::FromStr;
+ pub(super) fn serialize_items(
+ result: &CodegenResult,
+ context: &BindgenContext,
+ ) -> Result<(), CodegenError> {
+ if result.items_to_serialize.is_empty() {
+ return Ok(());
+ }
+
+ let path = context
+ .options()
+ .wrap_static_fns_path
+ .as_ref()
+ .map(PathBuf::from)
+ .unwrap_or_else(|| {
+ std::env::temp_dir().join("bindgen").join("extern")
+ });
+
+ let dir = path.parent().unwrap();
+
+ if !dir.exists() {
+ std::fs::create_dir_all(&dir)?;
+ }
+
+ let is_cpp = args_are_cpp(&context.options().clang_args) ||
+ context
+ .options()
+ .input_headers
+ .iter()
+ .any(|h| file_is_cpp(h));
+
+ let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" });
+
+ let mut code = Vec::new();
+
+ for &id in &result.items_to_serialize {
+ let item = context.resolve_item(id);
+ item.serialize(context, (), &mut vec![], &mut code)?;
+ }
+
+ std::fs::write(source_path, code)?;
+
+ Ok(())
+ }
+
pub fn prepend_bitfield_unit_type(
ctx: &BindgenContext,
result: &mut Vec<proc_macro2::TokenStream>,
diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs
new file mode 100644
index 00000000..217098e5
--- /dev/null
+++ b/bindgen/codegen/serialize.rs
@@ -0,0 +1,356 @@
+use std::io::Write;
+
+use crate::callbacks::IntKind;
+
+use crate::ir::comp::CompKind;
+use crate::ir::context::{BindgenContext, TypeId};
+use crate::ir::function::{Function, FunctionKind};
+use crate::ir::item::Item;
+use crate::ir::item::ItemCanonicalName;
+use crate::ir::item_kind::ItemKind;
+use crate::ir::ty::{FloatKind, Type, TypeKind};
+
+use super::CodegenError;
+
+fn get_loc(item: &Item) -> String {
+ item.location()
+ .map(|x| x.to_string())
+ .unwrap_or_else(|| "unknown".to_owned())
+}
+
+pub(crate) trait CSerialize<'a> {
+ type Extra;
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ extra: Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError>;
+}
+
+impl<'a> CSerialize<'a> for Item {
+ type Extra = ();
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ (): Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ match self.kind() {
+ ItemKind::Function(func) => {
+ func.serialize(ctx, self, stack, writer)
+ }
+ kind => {
+ return Err(CodegenError::Serialize {
+ msg: format!("Cannot serialize item kind {:?}", kind),
+ loc: get_loc(self),
+ });
+ }
+ }
+ }
+}
+
+impl<'a> CSerialize<'a> for Function {
+ type Extra = &'a Item;
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ item: Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ if self.kind() != FunctionKind::Function {
+ return Err(CodegenError::Serialize {
+ msg: format!(
+ "Cannot serialize function kind {:?}",
+ self.kind(),
+ ),
+ loc: get_loc(item),
+ });
+ }
+
+ let signature = match ctx.resolve_type(self.signature()).kind() {
+ TypeKind::Function(signature) => signature,
+ _ => unreachable!(),
+ };
+
+ let name = self.name();
+
+ // Function argoments stored as `(name, type_id)` tuples.
+ let args = {
+ let mut count = 0;
+
+ signature
+ .argument_types()
+ .iter()
+ .cloned()
+ .map(|(opt_name, type_id)| {
+ (
+ opt_name.unwrap_or_else(|| {
+ let name = format!("arg_{}", count);
+ count += 1;
+ name
+ }),
+ type_id,
+ )
+ })
+ .collect::<Vec<_>>()
+ };
+
+ // The name used for the wrapper self.
+ let wrap_name = format!("{}{}", name, ctx.wrap_static_fns_suffix());
+ // The function's return type
+ let ret_ty = signature.return_type();
+
+ // Write `ret_ty wrap_name(args) asm("wrap_name");`
+ ret_ty.serialize(ctx, (), stack, writer)?;
+ write!(writer, " {}(", wrap_name)?;
+ if args.is_empty() {
+ write!(writer, "void")?;
+ } else {
+ serialize_sep(
+ ", ",
+ args.iter(),
+ ctx,
+ writer,
+ |(name, type_id), ctx, buf| {
+ type_id.serialize(ctx, (), &mut vec![name.clone()], buf)
+ },
+ )?;
+ }
+ writeln!(writer, ") asm(\"{}\");", wrap_name)?;
+
+ // Write `ret_ty wrap_name(args) { return name(arg_names)' }`
+ ret_ty.serialize(ctx, (), stack, writer)?;
+ write!(writer, " {}(", wrap_name)?;
+ serialize_sep(
+ ", ",
+ args.iter(),
+ ctx,
+ writer,
+ |(name, type_id), _, buf| {
+ type_id.serialize(ctx, (), &mut vec![name.clone()], buf)
+ },
+ )?;
+ write!(writer, ") {{ return {}(", name)?;
+ serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| {
+ write!(buf, "{}", name).map_err(From::from)
+ })?;
+ writeln!(writer, "); }}")?;
+
+ Ok(())
+ }
+}
+
+impl<'a> CSerialize<'a> for TypeId {
+ type Extra = ();
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ (): Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ let item = ctx.resolve_item(*self);
+ item.expect_type().serialize(ctx, item, stack, writer)
+ }
+}
+
+impl<'a> CSerialize<'a> for Type {
+ type Extra = &'a Item;
+
+ fn serialize<W: Write>(
+ &self,
+ ctx: &BindgenContext,
+ item: Self::Extra,
+ stack: &mut Vec<String>,
+ writer: &mut W,
+ ) -> Result<(), CodegenError> {
+ match self.kind() {
+ TypeKind::Void => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ write!(writer, "void")?
+ }
+ TypeKind::NullPtr => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ write!(writer, "nullptr_t")?
+ }
+ TypeKind::Int(int_kind) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ match int_kind {
+ IntKind::Bool => write!(writer, "bool")?,
+ IntKind::SChar => write!(writer, "signed char")?,
+ IntKind::UChar => write!(writer, "unsigned char")?,
+ IntKind::WChar => write!(writer, "wchar_t")?,
+ IntKind::Short => write!(writer, "short")?,
+ IntKind::UShort => write!(writer, "unsigned short")?,
+ IntKind::Int => write!(writer, "int")?,
+ IntKind::UInt => write!(writer, "unsigned int")?,
+ IntKind::Long => write!(writer, "long")?,
+ IntKind::ULong => write!(writer, "unsigned long")?,
+ IntKind::LongLong => write!(writer, "long long")?,
+ IntKind::ULongLong => write!(writer, "unsigned long long")?,
+ IntKind::Char { .. } => write!(writer, "char")?,
+ int_kind => {
+ return Err(CodegenError::Serialize {
+ msg: format!(
+ "Cannot serialize integer kind {:?}",
+ int_kind
+ ),
+ loc: get_loc(item),
+ })
+ }
+ }
+ }
+ TypeKind::Float(float_kind) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ match float_kind {
+ FloatKind::Float => write!(writer, "float")?,
+ FloatKind::Double => write!(writer, "double")?,
+ FloatKind::LongDouble => write!(writer, "long double")?,
+ FloatKind::Float128 => write!(writer, "__float128")?,
+ }
+ }
+ TypeKind::Complex(float_kind) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ match float_kind {
+ FloatKind::Float => write!(writer, "float complex")?,
+ FloatKind::Double => write!(writer, "double complex")?,
+ FloatKind::LongDouble => {
+ write!(writer, "long double complex")?
+ }
+ FloatKind::Float128 => write!(writer, "__complex128")?,
+ }
+ }
+ TypeKind::Alias(type_id) => {
+ if let Some(name) = self.name() {
+ if self.is_const() {
+ write!(writer, "const {}", name)?;
+ } else {
+ write!(writer, "{}", name)?;
+ }
+ } else {
+ type_id.serialize(ctx, (), stack, writer)?;
+ }
+ }
+ TypeKind::Array(type_id, length) => {
+ type_id.serialize(ctx, (), stack, writer)?;
+ write!(writer, " [{}]", length)?
+ }
+ TypeKind::Function(signature) => {
+ if self.is_const() {
+ stack.push("const ".to_string());
+ }
+
+ signature.return_type().serialize(
+ ctx,
+ (),
+ &mut vec![],
+ writer,
+ )?;
+
+ write!(writer, " (")?;
+ while let Some(item) = stack.pop() {
+ write!(writer, "{}", item)?;
+ }
+ write!(writer, ")")?;
+
+ write!(writer, " (")?;
+ serialize_sep(
+ ", ",
+ signature.argument_types().iter(),
+ ctx,
+ writer,
+ |(name, type_id), ctx, buf| {
+ let mut stack = vec![];
+ if let Some(name) = name {
+ stack.push(name.clone());
+ }
+ type_id.serialize(ctx, (), &mut stack, buf)
+ },
+ )?;
+ write!(writer, ")")?
+ }
+ TypeKind::ResolvedTypeRef(type_id) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+ type_id.serialize(ctx, (), stack, writer)?
+ }
+ TypeKind::Pointer(type_id) => {
+ if self.is_const() {
+ stack.push("*const ".to_owned());
+ } else {
+ stack.push("*".to_owned());
+ }
+ type_id.serialize(ctx, (), stack, writer)?
+ }
+ TypeKind::Comp(comp_info) => {
+ if self.is_const() {
+ write!(writer, "const ")?;
+ }
+
+ let name = item.canonical_name(ctx);
+
+ match comp_info.kind() {
+ CompKind::Struct => write!(writer, "struct {}", name)?,
+ CompKind::Union => write!(writer, "union {}", name)?,
+ };
+ }
+ ty => {
+ return Err(CodegenError::Serialize {
+ msg: format!("Cannot serialize type kind {:?}", ty),
+ loc: get_loc(item),
+ })
+ }
+ };
+
+ if !stack.is_empty() {
+ write!(writer, " ")?;
+ while let Some(item) = stack.pop() {
+ write!(writer, "{}", item)?;
+ }
+ }
+
+ Ok(())
+ }
+}
+
+fn serialize_sep<
+ W: Write,
+ F: FnMut(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>,
+ I: Iterator,
+>(
+ sep: &str,
+ mut iter: I,
+ ctx: &BindgenContext,
+ buf: &mut W,
+ mut f: F,
+) -> Result<(), CodegenError> {
+ if let Some(item) = iter.next() {
+ f(item, ctx, buf)?;
+ let sep = sep.as_bytes();
+ for item in iter {
+ buf.write_all(sep)?;
+ f(item, ctx, buf)?;
+ }
+ }
+
+ Ok(())
+}
diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs
index c5df37d7..b693a704 100644
--- a/bindgen/ir/context.rs
+++ b/bindgen/ir/context.rs
@@ -20,6 +20,7 @@ use super::template::{TemplateInstantiation, TemplateParameters};
use super::traversal::{self, Edge, ItemTraversal};
use super::ty::{FloatKind, Type, TypeKind};
use crate::clang::{self, Cursor};
+use crate::codegen::CodegenError;
use crate::BindgenOptions;
use crate::{Entry, HashMap, HashSet};
use cexpr;
@@ -1146,9 +1147,9 @@ If you encounter an error missing from this list, please file an issue or a PR!"
pub(crate) fn gen<F, Out>(
mut self,
cb: F,
- ) -> (Out, BindgenOptions, Vec<String>)
+ ) -> Result<(Out, BindgenOptions, Vec<String>), CodegenError>
where
- F: FnOnce(&Self) -> Out,
+ F: FnOnce(&Self) -> Result<Out, CodegenError>,
{
self.in_codegen = true;
@@ -1183,8 +1184,8 @@ If you encounter an error missing from this list, please file an issue or a PR!"
self.compute_cannot_derive_hash();
self.compute_cannot_derive_partialord_partialeq_or_eq();
- let ret = cb(&self);
- (ret, self.options, self.warnings)
+ let ret = cb(&self)?;
+ Ok((ret, self.options, self.warnings))
}
/// When the `testing_only_extra_assertions` feature is enabled, this
@@ -2792,6 +2793,13 @@ If you encounter an error missing from this list, please file an issue or a PR!"
tokens.into_token_stream()
}
}
+
+ pub(crate) fn wrap_static_fns_suffix(&self) -> &str {
+ self.options()
+ .wrap_static_fns_suffix
+ .as_deref()
+ .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX)
+ }
}
/// A builder struct for configuring item resolution options.
diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs
index 8e83d980..baa2c36c 100644
--- a/bindgen/ir/function.rs
+++ b/bindgen/ir/function.rs
@@ -664,7 +664,6 @@ impl ClangSubItemParser for Function {
};
debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
-
let visibility = cursor.visibility();
if visibility != CXVisibility_Default {
return Err(ParseError::Continue);
@@ -674,25 +673,36 @@ impl ClangSubItemParser for Function {
return Err(ParseError::Continue);
}
+ let linkage = cursor.linkage();
+ let linkage = match linkage {
+ CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
+ CXLinkage_Internal => Linkage::Internal,
+ _ => return Err(ParseError::Continue),
+ };
+
if cursor.is_inlined_function() ||
cursor
.definition()
.map_or(false, |x| x.is_inlined_function())
{
- if !context.options().generate_inline_functions {
+ if !context.options().generate_inline_functions &&
+ !context.options().wrap_static_fns
+ {
return Err(ParseError::Continue);
}
+
if cursor.is_deleted_function() {
return Err(ParseError::Continue);
}
- }
- let linkage = cursor.linkage();
- let linkage = match linkage {
- CXLinkage_External | CXLinkage_UniqueExternal => Linkage::External,
- CXLinkage_Internal => Linkage::Internal,
- _ => return Err(ParseError::Continue),
- };
+ // We cannot handle `inline` functions that are not `static`.
+ if context.options().wrap_static_fns &&
+ cursor.is_inlined_function() &&
+ matches!(linkage, Linkage::External)
+ {
+ return Err(ParseError::Continue);
+ }
+ }
// Grab the signature using Item::from_ty.
let sig = Item::from_ty(&cursor.cur_type(), cursor, None, context)?;
@@ -727,7 +737,8 @@ impl ClangSubItemParser for Function {
let comment = cursor.raw_comment();
let function =
- Self::new(name, mangled_name, sig, comment, kind, linkage);
+ Self::new(name.clone(), mangled_name, sig, comment, kind, linkage);
+
Ok(ParseResult::New(function, Some(cursor)))
}
}
diff --git a/bindgen/lib.rs b/bindgen/lib.rs
index 8c8ffe5c..53747420 100644
--- a/bindgen/lib.rs
+++ b/bindgen/lib.rs
@@ -78,6 +78,7 @@ doc_mod!(ir, ir_docs);
doc_mod!(parse, parse_docs);
doc_mod!(regex_set, regex_set_docs);
+use codegen::CodegenError;
use ir::comment;
pub use crate::codegen::{
@@ -108,6 +109,7 @@ pub(crate) use std::collections::hash_map::Entry;
/// Default prefix for the anon fields.
pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_";
+const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern";
fn file_is_cpp(name_file: &str) -> bool {
name_file.ends_with(".hpp") ||
@@ -657,6 +659,23 @@ impl Builder {
for callbacks in &self.options.parse_callbacks {
output_vector.extend(callbacks.cli_args());
}
+ if self.options.wrap_static_fns {
+ output_vector.push("--wrap-static-fns".into())
+ }
+
+ if let Some(ref path) = self.options.wrap_static_fns_path {
+ output_vector.push("--wrap-static-fns-path".into());
+ output_vector.push(path.display().to_string());
+ }
+
+ if let Some(ref suffix) = self.options.wrap_static_fns_suffix {
+ output_vector.push("--wrap-static-fns-suffix".into());
+ output_vector.push(suffix.clone());
+ }
+
+ if cfg!(feature = "experimental") {
+ output_vector.push("--experimental".into());
+ }
// Add clang arguments
@@ -1553,33 +1572,25 @@ impl Builder {
}
/// Generate the Rust bindings using the options built up thus far.
- pub fn generate(self) -> Result<Bindings, BindgenError> {
- let mut options = self.options.clone();
+ pub fn generate(mut self) -> Result<Bindings, BindgenError> {
// Add any extra arguments from the environment to the clang command line.
- options.clang_args.extend(get_extra_clang_args());
+ self.options.clang_args.extend(get_extra_clang_args());
// Transform input headers to arguments on the clang command line.
- options.clang_args.extend(
- options.input_headers
- [..options.input_headers.len().saturating_sub(1)]
+ self.options.clang_args.extend(
+ self.options.input_headers
+ [..self.options.input_headers.len().saturating_sub(1)]
.iter()
.flat_map(|header| ["-include".into(), header.to_string()]),
);
let input_unsaved_files =
- std::mem::take(&mut options.input_header_contents)
+ std::mem::take(&mut self.options.input_header_contents)
.into_iter()
.map(|(name, contents)| clang::UnsavedFile::new(name, contents))
.collect::<Vec<_>>();
- match Bindings::generate(options, input_unsaved_files) {
- GenerateResult::Ok(bindings) => Ok(*bindings),
- GenerateResult::ShouldRestart { header } => self
- .header(header)
- .generate_inline_functions(false)
- .generate(),
- GenerateResult::Err(err) => Err(err),
- }
+ Bindings::generate(self.options, input_unsaved_files)
}
/// Preprocess and dump the input header files to disk.
@@ -1796,6 +1807,32 @@ impl Builder {
self.options.wrap_unsafe_ops = doit;
self
}
+
+ #[cfg(feature = "experimental")]
+ /// Whether to generate extern wrappers for `static` and `static inline` functions. Defaults to
+ /// false.
+ pub fn wrap_static_fns(mut self, doit: bool) -> Self {
+ self.options.wrap_static_fns = doit;
+ self
+ }
+
+ #[cfg(feature = "experimental")]
+ /// Set the path for the source code file that would be created if any wrapper functions must
+ /// be generated due to the presence of static functions.
+ ///
+ /// Bindgen will automatically add the right extension to the header and source code files.
+ pub fn wrap_static_fns_path<T: AsRef<Path>>(mut self, path: T) -> Self {
+ self.options.wrap_static_fns_path = Some(path.as_ref().to_owned());
+ self
+ }
+
+ #[cfg(feature = "experimental")]
+ /// Set the suffix added to the extern wrapper functions generated for `static` and `static
+ /// inline` functions.
+ pub fn wrap_static_fns_suffix<T: AsRef<str>>(mut self, suffix: T) -> Self {
+ self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned());
+ self
+ }
}
/// Configuration options for generated bindings.
@@ -2136,6 +2173,12 @@ struct BindgenOptions {
/// Whether to wrap unsafe operations in unsafe blocks or not.
wrap_unsafe_ops: bool,
+
+ wrap_static_fns: bool,
+
+ wrap_static_fns_suffix: Option<String>,
+
+ wrap_static_fns_path: Option<PathBuf>,
}
impl BindgenOptions {
@@ -2328,6 +2371,9 @@ impl Default for BindgenOptions {
merge_extern_blocks,
abi_overrides,
wrap_unsafe_ops,
+ wrap_static_fns,
+ wrap_static_fns_suffix,
+ wrap_static_fns_path,
}
}
}
@@ -2358,18 +2404,6 @@ fn ensure_libclang_is_loaded() {
#[cfg(not(feature = "runtime"))]
fn ensure_libclang_is_loaded() {}
-#[derive(Debug)]
-enum GenerateResult {
- Ok(Box<Bindings>),
- /// Error variant raised when bindgen requires to run again with a newly generated header
- /// input.
- #[allow(dead_code)]
- ShouldRestart {
- header: String,
- },
- Err(BindgenError),
-}
-
/// Error type for rust-bindgen.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
@@ -2382,6 +2416,8 @@ pub enum BindgenError {
NotExist(PathBuf),
/// Clang diagnosed an error.
ClangDiagnostic(String),
+ /// Code generation reported an error.
+ Codegen(CodegenError),
}
impl std::fmt::Display for BindgenError {
@@ -2399,6 +2435,9 @@ impl std::fmt::Display for BindgenError {
BindgenError::ClangDiagnostic(message) => {
write!(f, "clang diagnosed error: {}", message)
}
+ BindgenError::Codegen(err) => {
+ write!(f, "codegen error: {}", err)
+ }
}
}
}
@@ -2472,7 +2511,7 @@ impl Bindings {
pub(crate) fn generate(
mut options: BindgenOptions,
input_unsaved_files: Vec<clang::UnsavedFile>,
- ) -> GenerateResult {
+ ) -> Result<Bindings, BindgenError> {
ensure_libclang_is_loaded();
#[cfg(feature = "runtime")]
@@ -2593,21 +2632,17 @@ impl Bindings {
let path = Path::new(h);
if let Ok(md) = std::fs::metadata(path) {
if md.is_dir() {
- return GenerateResult::Err(BindgenError::FolderAsHeader(
- path.into(),
- ));
+ return Err(BindgenError::FolderAsHeader(path.into()));
}
if !can_read(&md.permissions()) {
- return GenerateResult::Err(
- BindgenError::InsufficientPermissions(path.into()),
- );
+ return Err(BindgenError::InsufficientPermissions(
+ path.into(),
+ ));
}
let h = h.clone();
options.clang_args.push(h);
} else {
- return GenerateResult::Err(BindgenError::NotExist(
- path.into(),
- ));
+ return Err(BindgenError::NotExist(path.into()));
}
}
@@ -2635,18 +2670,17 @@ impl Bindings {
{
let _t = time::Timer::new("parse").with_output(time_phases);
- if let Err(err) = parse(&mut context) {
- return GenerateResult::Err(err);
- }
+ parse(&mut context)?;
}
- let (module, options, warnings) = codegen::codegen(context);
+ let (module, options, warnings) =
+ codegen::codegen(context).map_err(BindgenError::Codegen)?;
- GenerateResult::Ok(Box::new(Bindings {
+ Ok(Bindings {
options,
warnings,
module,
- }))
+ })
}
/// Write these bindings as source text to a file.