From afbc4d8dcb6a50908d91acbaf191c191f61e4856 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 4 Nov 2022 12:55:27 -0500 Subject: [PATCH 01/37] Generate extern wrappers for inlined functions If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=`: Adds to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=`: Uses as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=`: Creates the source and header files inside (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes #1090. --- bindgen-cli/options.rs | 32 +++ .../tests/generate-extern-functions.rs | 15 ++ .../tests/headers/generate-extern-functions.h | 11 + bindgen/codegen/mod.rs | 21 +- bindgen/ir/context.rs | 5 + bindgen/ir/function.rs | 16 +- bindgen/ir/mod.rs | 1 + bindgen/ir/serialize.rs | 234 ++++++++++++++++++ bindgen/lib.rs | 161 +++++++++++- 9 files changed, 487 insertions(+), 9 deletions(-) create mode 100644 bindgen-tests/tests/expectations/tests/generate-extern-functions.rs create mode 100644 bindgen-tests/tests/headers/generate-extern-functions.h create mode 100644 bindgen/ir/serialize.rs diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index 2b09d85fd9..e84b0a05cb 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -353,6 +353,18 @@ struct BindgenCommand { /// Derive custom traits on a `union`. The value must be of the shape = where is a coma-separated list of derive macros. #[arg(long, value_name = "CUSTOM")] with_derive_custom_union: Vec, + /// Generate extern wrappers for inlined functions + #[arg(long)] + generate_extern_functions: bool, + /// Sets the name of the header and source code files that would be created if any extern wrapper functions must be generated due to the presence of inlined functions. + #[arg(long, value_name = "FILENAME")] + extern_functions_file_name: Option, + #[arg(long, value_name = "DIRECTORY")] + /// Sets the directory path where any extra files must be created due to the presence of inlined functions. + extern_functions_directory: Option, + /// Sets the suffix added to the extern wrapper functions generated for inlined functions. + #[arg(long, value_name = "SUFFIX")] + extern_function_suffix: Option, /// Prints the version, and exits #[arg(short = 'V', long)] version: bool, @@ -473,6 +485,10 @@ where with_derive_custom_struct, with_derive_custom_enum, with_derive_custom_union, + generate_extern_functions, + extern_functions_file_name, + extern_functions_directory, + extern_function_suffix, version, clang_args, } = command; @@ -978,5 +994,21 @@ where } } + if generate_extern_functions { + builder = builder.generate_extern_functions(true); + } + + if let Some(file_name) = extern_functions_file_name { + builder = builder.extern_functions_file_name(file_name); + } + + if let Some(directory) = extern_functions_directory { + builder = builder.extern_functions_directory(directory); + } + + if let Some(suffix) = extern_function_suffix { + builder = builder.extern_function_suffix(suffix); + } + Ok((builder, output, verbose)) } diff --git a/bindgen-tests/tests/expectations/tests/generate-extern-functions.rs b/bindgen-tests/tests/expectations/tests/generate-extern-functions.rs new file mode 100644 index 0000000000..c4b81f1a0b --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/generate-extern-functions.rs @@ -0,0 +1,15 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +extern "C" { + #[link_name = "\u{1}foo__extern"] + pub fn foo() -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}bar__extern"] + pub fn bar() -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/headers/generate-extern-functions.h b/bindgen-tests/tests/headers/generate-extern-functions.h new file mode 100644 index 0000000000..dacd69fd2c --- /dev/null +++ b/bindgen-tests/tests/headers/generate-extern-functions.h @@ -0,0 +1,11 @@ +// bindgen-flags: --generate-extern-functions + +static inline int foo() { + return 0; +} +static int bar() { + return 1; +} +inline int baz() { + return 2; +} diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 6b24ae1bd0..309ccb65f0 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4002,9 +4002,8 @@ impl CodeGenerator for Function { // 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 => {} + if matches!(self.linkage(), Linkage::Internal) { + return None; } // Pure virtual methods have no actual symbol, so we can't generate @@ -4114,6 +4113,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 +4123,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 +4134,20 @@ impl CodeGenerator for Function { quote! { #[link(wasm_import_module = #name)] } }); + if ctx.options().generate_extern_functions.is_second_run() { + if let Some(name) = canonical_name.strip_suffix( + ctx.options() + .extern_function_suffix + .as_deref() + .unwrap_or(crate::DEFAULT_EXTERN_FUNCTION_SUFFIX), + ) { + if !has_link_name_attr { + attributes.push(attributes::link_name(&canonical_name)); + } + canonical_name = name.to_owned(); + } + } + let ident = ctx.rust_ident(canonical_name); let tokens = quote! { #wasm_link_attribute diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index c5df37d7e9..f82237f25d 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -16,6 +16,7 @@ use super::int::IntKind; use super::item::{IsOpaque, Item, ItemAncestors, ItemSet}; use super::item_kind::ItemKind; use super::module::{Module, ModuleKind}; +use super::serialize::CItem; use super::template::{TemplateInstantiation, TemplateParameters}; use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, Type, TypeKind}; @@ -477,6 +478,9 @@ pub struct BindgenContext { /// The set of warnings raised during binding generation. warnings: Vec, + + /// C items that need to be serialized to an extra header file. + pub(crate) c_items: Vec, } /// A traversal of allowlisted items. @@ -593,6 +597,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" has_type_param_in_array: None, has_float: None, warnings: Vec::new(), + c_items: Vec::new(), } } diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 8e83d980bc..8d976950e3 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -8,6 +8,7 @@ use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::TypeKind; use crate::callbacks::{ItemInfo, ItemKind}; use crate::clang::{self, Attribute}; +use crate::ir::serialize::CItem; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; use clang_sys::{self, CXCallingConv}; use proc_macro2; @@ -679,9 +680,12 @@ impl ClangSubItemParser for Function { .definition() .map_or(false, |x| x.is_inlined_function()) { - if !context.options().generate_inline_functions { + if !(context.options().generate_inline_functions || + context.options().generate_extern_functions.is_true()) + { return Err(ParseError::Continue); } + if cursor.is_deleted_function() { return Err(ParseError::Continue); } @@ -728,6 +732,16 @@ impl ClangSubItemParser for Function { let function = Self::new(name, mangled_name, sig, comment, kind, linkage); + + if matches!(linkage, Linkage::Internal) && + context.options().generate_extern_functions.is_true() + { + match CItem::from_function(&function, context) { + Ok(c_item) => context.c_items.push(c_item), + Err(err) => warn!("Serialization failed: {:?}", err), + } + } + Ok(ParseResult::New(function, Some(cursor))) } } diff --git a/bindgen/ir/mod.rs b/bindgen/ir/mod.rs index 8f6a2dac88..bb76e2ab4b 100644 --- a/bindgen/ir/mod.rs +++ b/bindgen/ir/mod.rs @@ -18,6 +18,7 @@ pub mod item_kind; pub mod layout; pub mod module; pub mod objc; +pub(crate) mod serialize; pub mod template; pub mod traversal; pub mod ty; diff --git a/bindgen/ir/serialize.rs b/bindgen/ir/serialize.rs new file mode 100644 index 0000000000..bc480acaa5 --- /dev/null +++ b/bindgen/ir/serialize.rs @@ -0,0 +1,234 @@ +use std::fmt::{self, Write}; + +use crate::callbacks::IntKind; +use crate::DEFAULT_EXTERN_FUNCTION_SUFFIX; + +use super::context::{BindgenContext, TypeId}; +use super::function::{Function, FunctionKind}; +use super::ty::{FloatKind, TypeKind}; + +#[derive(Debug)] +pub(crate) enum Error { + Serialize(String), + Fmt(fmt::Error), +} + +impl From for Error { + fn from(err: fmt::Error) -> Self { + Self::Fmt(err) + } +} + +impl From for Error { + fn from(err: String) -> Self { + Self::Serialize(err) + } +} + +#[derive(Debug)] +pub(crate) struct CItem { + header: String, + code: String, +} + +impl CItem { + pub(crate) fn from_function( + function: &Function, + ctx: &BindgenContext, + ) -> Result { + match function.kind() { + FunctionKind::Function => { + let signature_type = ctx.resolve_type(function.signature()); + match signature_type.kind() { + TypeKind::Function(signature) => { + let mut buf = String::new(); + + let mut count = 0; + + let name = function.name(); + let args = 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::>(); + + serialize_type(signature.return_type(), ctx, &mut buf)?; + write!( + buf, + " {}{}(", + name, + ctx.options() + .extern_function_suffix + .as_deref() + .unwrap_or(DEFAULT_EXTERN_FUNCTION_SUFFIX) + )?; + serialize_sep( + ", ", + args.iter(), + ctx, + &mut buf, + |(name, type_id), ctx, buf| { + serialize_type(*type_id, ctx, buf)?; + write!(buf, " {}", name).map_err(Error::from) + }, + )?; + write!(buf, ")")?; + + let header = format!("{};", buf); + + write!(buf, " {{ return {}(", name)?; + serialize_sep( + ", ", + args.iter(), + ctx, + &mut buf, + |(name, _), _, buf| { + write!(buf, "{}", name).map_err(Error::from) + }, + )?; + write!(buf, "); }}")?; + + Ok(Self { header, code: buf }) + } + _ => unreachable!(), + } + } + function_kind => Err(Error::Serialize(format!( + "Cannot serialize function kind {:?}", + function_kind + ))), + } + } + + pub(crate) fn header(&self) -> &str { + self.header.as_ref() + } + + pub(crate) fn code(&self) -> &str { + self.code.as_ref() + } +} + +fn serialize_sep< + W: fmt::Write, + F: Fn(I::Item, &BindgenContext, &mut W) -> Result<(), Error>, + I: Iterator, +>( + sep: &'static str, + mut iter: I, + ctx: &BindgenContext, + buf: &mut W, + f: F, +) -> Result<(), Error> { + if let Some(item) = iter.next() { + f(item, ctx, buf)?; + + for item in iter { + write!(buf, "{}", sep)?; + f(item, ctx, buf)?; + } + } + + Ok(()) +} + +fn serialize_type( + type_id: TypeId, + ctx: &BindgenContext, + buf: &mut W, +) -> Result<(), Error> { + match ctx.resolve_type(type_id).kind() { + TypeKind::Void => write!(buf, "void")?, + TypeKind::NullPtr => write!(buf, "nullptr_t")?, + TypeKind::Int(int_kind) => match int_kind { + IntKind::Bool => write!(buf, "bool")?, + IntKind::SChar => write!(buf, "signed char")?, + IntKind::UChar => write!(buf, "unsigned char")?, + IntKind::WChar => write!(buf, "wchar_t")?, + IntKind::Short => write!(buf, "short")?, + IntKind::UShort => write!(buf, "unsigned short")?, + IntKind::Int => write!(buf, "int")?, + IntKind::UInt => write!(buf, "unsigned int")?, + IntKind::Long => write!(buf, "long")?, + IntKind::ULong => write!(buf, "unsigned long")?, + IntKind::LongLong => write!(buf, "long long")?, + IntKind::ULongLong => write!(buf, "unsigned long long")?, + int_kind => { + return Err(Error::Serialize(format!( + "Cannot serialize integer kind {:?}", + int_kind + ))) + } + }, + TypeKind::Float(float_kind) => match float_kind { + FloatKind::Float => write!(buf, "float")?, + FloatKind::Double => write!(buf, "double")?, + FloatKind::LongDouble => write!(buf, "long double")?, + FloatKind::Float128 => write!(buf, "__float128")?, + }, + TypeKind::Complex(float_kind) => match float_kind { + FloatKind::Float => write!(buf, "float complex")?, + FloatKind::Double => write!(buf, "double complex")?, + FloatKind::LongDouble => write!(buf, "long double complex")?, + FloatKind::Float128 => write!(buf, "__complex128")?, + }, + TypeKind::Alias(type_id) => serialize_type(*type_id, ctx, buf)?, + TypeKind::TemplateAlias(type_id, params) => { + serialize_type(*type_id, ctx, buf)?; + write!(buf, "<")?; + serialize_sep( + ", ", + params.iter().copied(), + ctx, + buf, + serialize_type, + )?; + write!(buf, ">")? + } + TypeKind::Array(type_id, length) => { + serialize_type(*type_id, ctx, buf)?; + write!(buf, " [{}]", length)? + } + TypeKind::Function(signature) => { + serialize_type(signature.return_type(), ctx, buf)?; + write!(buf, " (")?; + serialize_sep( + ", ", + signature.argument_types().iter(), + ctx, + buf, + |(name, type_id), ctx, buf| { + serialize_type(*type_id, ctx, buf)?; + + if let Some(name) = name { + write!(buf, "{}", name)?; + } + + Ok(()) + }, + )?; + write!(buf, ")")? + } + TypeKind::ResolvedTypeRef(type_id) => { + serialize_type(*type_id, ctx, buf)? + } + ty => { + return Err(Error::Serialize(format!( + "Cannot serialize type kind {:?}", + ty + ))) + } + }; + + Ok(()) +} diff --git a/bindgen/lib.rs b/bindgen/lib.rs index cf1486c2d2..2c3210f981 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -108,6 +108,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_EXTERN_FUNCTION_SUFFIX: &str = "__extern"; fn file_is_cpp(name_file: &str) -> bool { name_file.ends_with(".hpp") || @@ -657,6 +658,24 @@ impl Builder { for callbacks in &self.options.parse_callbacks { output_vector.extend(callbacks.cli_args()); } + if self.options.generate_extern_functions.is_true() { + output_vector.push("--generate-extern-functions".into()) + } + + if let Some(ref file_name) = self.options.extern_functions_file_name { + output_vector.push("--extern-functions-file-name".into()); + output_vector.push(file_name.clone()); + } + + if let Some(ref directory) = self.options.extern_functions_directory { + output_vector.push("--extern-functions-directory".into()); + output_vector.push(directory.display().to_string()); + } + + if let Some(ref suffix) = self.options.extern_function_suffix { + output_vector.push("--extern-function-suffix".into()); + output_vector.push(suffix.clone()); + } // Add clang arguments @@ -1574,10 +1593,9 @@ impl Builder { match Bindings::generate(options, input_unsaved_files) { GenerateResult::Ok(bindings) => Ok(*bindings), - GenerateResult::ShouldRestart { header } => self - .header(header) - .generate_inline_functions(false) - .generate(), + GenerateResult::ShouldRestart { header } => { + self.second_run(header).generate() + } GenerateResult::Err(err) => Err(err), } } @@ -1796,6 +1814,73 @@ impl Builder { self.options.wrap_unsafe_ops = doit; self } + + /// Whether to generate extern wrappers for inline functions. Defaults to false. + pub fn generate_extern_functions(mut self, doit: bool) -> Self { + self.options.generate_extern_functions = if doit { + GenerateExternFunctions::True + } else { + GenerateExternFunctions::False + }; + self + } + + /// Set the name of the header and source code files that would be created if any extern + /// wrapper functions must be generated due to the presence of inlined functions. + pub fn extern_functions_file_name>( + mut self, + file_name: T, + ) -> Self { + self.options.extern_functions_file_name = + Some(file_name.as_ref().to_owned()); + self + } + + /// Set the directory path where any extra files must be created due to the presence of inlined + /// functions. + pub fn extern_functions_directory>( + mut self, + directory: T, + ) -> Self { + self.options.extern_functions_directory = + Some(directory.as_ref().to_owned().into()); + self + } + + /// Set the suffix added to the extern wrapper functions generated for inlined functions. + pub fn extern_function_suffix>(mut self, suffix: T) -> Self { + self.options.extern_function_suffix = Some(suffix.as_ref().to_owned()); + self + } + + fn second_run(mut self, extra_header: String) -> Self { + self.options.generate_extern_functions = + GenerateExternFunctions::SecondRun; + self.header(extra_header) + } +} + +#[derive(Clone, Copy, Debug)] +enum GenerateExternFunctions { + True, + False, + SecondRun, +} + +impl GenerateExternFunctions { + fn is_true(self) -> bool { + matches!(self, Self::True) + } + + fn is_second_run(self) -> bool { + matches!(self, Self::SecondRun) + } +} + +impl Default for GenerateExternFunctions { + fn default() -> Self { + Self::False + } } /// Configuration options for generated bindings. @@ -2136,6 +2221,14 @@ struct BindgenOptions { /// Whether to wrap unsafe operations in unsafe blocks or not. wrap_unsafe_ops: bool, + + generate_extern_functions: GenerateExternFunctions, + + extern_function_suffix: Option, + + extern_functions_directory: Option, + + extern_functions_file_name: Option, } impl BindgenOptions { @@ -2328,6 +2421,10 @@ impl Default for BindgenOptions { merge_extern_blocks, abi_overrides, wrap_unsafe_ops, + generate_extern_functions, + extern_function_suffix, + extern_functions_directory, + extern_functions_file_name, } } } @@ -2363,7 +2460,6 @@ enum GenerateResult { Ok(Box), /// Error variant raised when bindgen requires to run again with a newly generated header /// input. - #[allow(dead_code)] ShouldRestart { header: String, }, @@ -2631,6 +2727,61 @@ impl Bindings { } } + fn serialize_c_items( + context: &BindgenContext, + ) -> Result { + let dir = context + .options() + .extern_functions_directory + .clone() + .unwrap_or_else(|| std::env::temp_dir().join("bindgen")); + + if !dir.exists() { + std::fs::create_dir_all(&dir)?; + } + + let path = std::fs::canonicalize(dir)?.join( + context + .options() + .extern_functions_file_name + .as_deref() + .unwrap_or("extern"), + ); + + let is_cpp = args_are_cpp(&context.options().clang_args) || + context + .options() + .input_headers + .iter() + .any(|h| file_is_cpp(h)); + + let headers_path = + path.with_extension(if is_cpp { "hpp" } else { "h" }); + let source_path = + path.with_extension(if is_cpp { "cpp" } else { "c" }); + + let mut headers_file = File::create(&headers_path)?; + let mut source_file = File::create(source_path)?; + + for item in &context.c_items { + writeln!(headers_file, "{}", item.header())?; + writeln!(source_file, "{}", item.code())?; + } + + Ok(headers_path) + } + + if !context.c_items.is_empty() { + match serialize_c_items(&context) { + Ok(headers) => { + return GenerateResult::ShouldRestart { + header: headers.display().to_string(), + } + } + Err(err) => warn!("Could not serialize C items: {}", err), + } + } + let (module, options, warnings) = codegen::codegen(context); GenerateResult::Ok(Box::new(Bindings { From ad0f16123b6469e74c6c644a483294adec905b4f Mon Sep 17 00:00:00 2001 From: Amanjeev Sethi Date: Thu, 19 Jan 2023 15:38:54 -0500 Subject: [PATCH 02/37] add(static inlined): tests test(static inlined): pretty print the diff Issue: GH-1090 test(static inlined): refactor paths once again - Because directory structure is confusing to the author of this commit GH-1090 test(static inlined): refactor test files - Expected files should be under tests/expectations/generated - Remove extern_stub.h because we can reuse the header from generate-extern-functions.h test(static inlined): diff test; generated files refactor(static inlined): integration test Issue: GH-1090 GH-1090: Integration tests integration test: document the GH issue integration test (macro): same order in impl as the trait for consistency integration test: move each setup into its own function, just to save face inline static func integration test resolve accidental conflict --- bindgen-integration/build.rs | 118 +++++++++++++----- bindgen-integration/src/lib.rs | 16 +++ .../expectations/tests/generated/README.md | 4 + .../expectations/tests/generated/extern.c | 2 + .../expectations/tests/generated/extern.h | 2 + .../tests/headers/generate-extern-functions.h | 2 +- bindgen-tests/tests/tests.rs | 50 ++++++++ 7 files changed, 165 insertions(+), 29 deletions(-) create mode 100644 bindgen-tests/tests/expectations/tests/generated/README.md create mode 100644 bindgen-tests/tests/expectations/tests/generated/extern.c create mode 100644 bindgen-tests/tests/expectations/tests/generated/extern.h diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 0f30ad470f..9b97e84e45 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -4,7 +4,7 @@ extern crate cc; use bindgen::callbacks::{ DeriveInfo, IntKind, MacroParsingBehavior, ParseCallbacks, }; -use bindgen::{Builder, EnumVariation}; +use bindgen::{Builder, CargoCallbacks, EnumVariation}; use std::collections::HashSet; use std::env; use std::path::PathBuf; @@ -28,21 +28,14 @@ impl ParseCallbacks for MacroCallback { MacroParsingBehavior::Default } - fn item_name(&self, original_item_name: &str) -> Option { - if original_item_name.starts_with("my_prefixed_") { - Some( - original_item_name - .trim_start_matches("my_prefixed_") - .to_string(), - ) - } else if original_item_name.starts_with("MY_PREFIXED_") { - Some( - original_item_name - .trim_start_matches("MY_PREFIXED_") - .to_string(), - ) - } else { - None + fn int_macro(&self, name: &str, _value: i64) -> Option { + match name { + "TESTMACRO_CUSTOMINTKIND_PATH" => Some(IntKind::Custom { + name: "crate::MacroInteger", + is_signed: true, + }), + + _ => None, } } @@ -67,17 +60,6 @@ impl ParseCallbacks for MacroCallback { } } - fn int_macro(&self, name: &str, _value: i64) -> Option { - match name { - "TESTMACRO_CUSTOMINTKIND_PATH" => Some(IntKind::Custom { - name: "crate::MacroInteger", - is_signed: true, - }), - - _ => None, - } - } - fn func_macro(&self, name: &str, value: &[&[u8]]) { match name { "TESTMACRO_NONFUNCTIONAL" => { @@ -122,6 +104,24 @@ impl ParseCallbacks for MacroCallback { } } + fn item_name(&self, original_item_name: &str) -> Option { + if original_item_name.starts_with("my_prefixed_") { + Some( + original_item_name + .trim_start_matches("my_prefixed_") + .to_string(), + ) + } else if original_item_name.starts_with("MY_PREFIXED_") { + Some( + original_item_name + .trim_start_matches("MY_PREFIXED_") + .to_string(), + ) + } else { + None + } + } + // Test the "custom derives" capability by adding `PartialEq` to the `Test` struct. fn add_derives(&self, info: &DeriveInfo<'_>) -> Vec { if info.name == "Test" { @@ -149,7 +149,7 @@ impl Drop for MacroCallback { } } -fn main() { +fn setup_macro_test() { cc::Build::new() .cpp(true) .file("cpp/Test.cc") @@ -204,3 +204,65 @@ fn main() { "including stub via include dir must produce correct dep path", ); } + +fn setup_extern_test() { + // GH-1090: https://github.com/rust-lang/rust-bindgen/issues/1090 + // set output directory under /target so it is easy to clean generated files + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let out_rust_file = out_path.join("extern.rs"); + + let input_header_dir = PathBuf::from("../bindgen-tests/tests/headers/").canonicalize() + .expect("Cannot canonicalize libdir path"); + let input_header_file_path = input_header_dir.join("generate-extern-functions.h"); + let input_header_file_path_str = input_header_file_path.to_str() + .expect("Path could not be converted to a str"); + + // generate external bindings with the external .c and .h files + let bindings = Builder::default() + .header(input_header_file_path_str) + .parse_callbacks(Box::new(CargoCallbacks)) + .generate_extern_functions(true) + .extern_functions_directory(out_path.display().to_string()) + .generate() + .expect("Unable to generate bindings"); + + println!("cargo:rustc-link-lib=extern"); // tell cargo to link libextern + println!("bindings generated: {}", bindings); + + let obj_path = out_path.join("extern.o"); + let lib_path = out_path.join("libextern.a"); + + // build the external files to check if they work + if !std::process::Command::new("clang") + .arg("-c") + .arg("-o") + .arg(&obj_path) + .arg(out_path.join("extern.c")) + .arg("-include") + .arg(input_header_file_path) + .output() + .expect("`clang` command error") + .status + .success() { + panic!("Could not compile object file"); + } + + if !std::process::Command::new("ar") + .arg("rcs") + .arg(lib_path) + .arg(obj_path) + .output() + .expect("`ar` command error") + .status + .success() { + panic!("Could not emit library file"); + } + + bindings.write_to_file(out_rust_file) + .expect("Cound not write bindings to the Rust file"); +} + +fn main() { + setup_macro_test(); + setup_extern_test(); +} diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 43f71580d2..f5ef8644b9 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -4,6 +4,10 @@ mod bindings { include!(concat!(env!("OUT_DIR"), "/test.rs")); } +mod extern_bindings { + include!(concat!(env!("OUT_DIR"), "/extern.rs")); +} + use std::ffi::CStr; use std::mem; use std::os::raw::c_int; @@ -286,3 +290,15 @@ fn test_custom_derive() { assert!(meter < lightyear); assert!(meter > micron); } + +#[test] +fn test_extern_bindings() { + // GH-1090: https://github.com/rust-lang/rust-bindgen/issues/1090 + unsafe { + let f = extern_bindings::foo(); + assert_eq!(11, f); + + let b = extern_bindings::bar(); + assert_eq!(1, b); + } +} diff --git a/bindgen-tests/tests/expectations/tests/generated/README.md b/bindgen-tests/tests/expectations/tests/generated/README.md new file mode 100644 index 0000000000..7b9eea412c --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/generated/README.md @@ -0,0 +1,4 @@ +# Generated C, C++, Header files + +This directory contains files for features where extra files are generated +as a part of the feature. For example, `--generated-extern-functions`. \ No newline at end of file diff --git a/bindgen-tests/tests/expectations/tests/generated/extern.c b/bindgen-tests/tests/expectations/tests/generated/extern.c new file mode 100644 index 0000000000..f6e1ad01ec --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/generated/extern.c @@ -0,0 +1,2 @@ +int foo__extern() { return foo(); } +int bar__extern() { return bar(); } diff --git a/bindgen-tests/tests/expectations/tests/generated/extern.h b/bindgen-tests/tests/expectations/tests/generated/extern.h new file mode 100644 index 0000000000..cd99194f26 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/generated/extern.h @@ -0,0 +1,2 @@ +int foo__extern(); +int bar__extern(); diff --git a/bindgen-tests/tests/headers/generate-extern-functions.h b/bindgen-tests/tests/headers/generate-extern-functions.h index dacd69fd2c..e5b20f746f 100644 --- a/bindgen-tests/tests/headers/generate-extern-functions.h +++ b/bindgen-tests/tests/headers/generate-extern-functions.h @@ -1,7 +1,7 @@ // bindgen-flags: --generate-extern-functions static inline int foo() { - return 0; + return 11; } static int bar() { return 1; diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 25c073cc84..16286b1299 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -713,3 +713,53 @@ fn commandline_multiple_headers() { .header("tests/headers/16-byte-alignment.h"); build_flags_output_helper(&bindings); } + +#[test] +fn test_extern_generated_headers() { + // This test is for testing diffs of the generated C source and header files + // TODO: If another such feature is added, convert this test into a more generic + // test that looks at `tests/headers/generated` directory. + let expect_path = PathBuf::from("tests/expectations/tests/generated"); + println!("In path is ::: {}", expect_path.to_str().unwrap()); + + let generated_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + println!("Out path is ::: {}", generated_path.to_str().unwrap()); + + let _bindings = Builder::default() + .header("tests/headers/generate-extern-functions.h") + .generate_extern_functions(true) + .extern_functions_directory(generated_path.display().to_string()) + .generate() + .expect("Failed to generate bindings"); + + let expected_c = fs::read_to_string(expect_path.join("extern.c")) + .expect("Could not read generated extern.c"); + let expected_h = fs::read_to_string(expect_path.join("extern.h")) + .expect("Could not read generated extern.h"); + + let actual_c = fs::read_to_string(generated_path.join("extern.c")) + .expect("Could not read actual extern.c"); + let actual_h = fs::read_to_string(generated_path.join("extern.h")) + .expect("Could not read actual extern.h"); + + if expected_c != actual_c { + error_diff_mismatch( + &actual_c, + &expected_c, + None, + Path::new(expect_path.join("extern.c").to_str().unwrap()), + ) + .unwrap(); + } + + if expected_h != actual_h { + error_diff_mismatch( + &actual_h, + &expected_h, + None, + Path::new(expect_path.join("extern.h").to_str().unwrap()), + ) + .unwrap(); + } + +} \ No newline at end of file From 101cde0cbbb58c82c356924e2d2b0767604acad6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Jan 2023 14:29:12 -0500 Subject: [PATCH 03/37] add the `experimental` feature --- bindgen-cli/Cargo.toml | 2 +- bindgen-cli/options.rs | 12 +++++++---- bindgen-integration/build.rs | 20 ++++++++++++------- bindgen-tests/Cargo.toml | 2 +- .../tests/headers/generate-extern-functions.h | 2 +- bindgen-tests/tests/tests.rs | 7 +++---- bindgen/Cargo.toml | 1 + bindgen/lib.rs | 8 ++++++++ 8 files changed, 36 insertions(+), 18 deletions(-) diff --git a/bindgen-cli/Cargo.toml b/bindgen-cli/Cargo.toml index b900d9406d..10b4d4cd28 100644 --- a/bindgen-cli/Cargo.toml +++ b/bindgen-cli/Cargo.toml @@ -21,7 +21,7 @@ path = "main.rs" name = "bindgen" [dependencies] -bindgen = { path = "../bindgen", version = "=0.63.0", features = ["cli"] } +bindgen = { path = "../bindgen", version = "=0.63.0", features = ["cli", "experimental"] } shlex = "1" clap = { version = "4", features = ["derive"] } env_logger = { version = "0.9.0", optional = true } diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index e84b0a05cb..d6459b41e1 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -354,17 +354,20 @@ struct BindgenCommand { #[arg(long, value_name = "CUSTOM")] with_derive_custom_union: Vec, /// Generate extern wrappers for inlined functions - #[arg(long)] + #[arg(long, requires = "experimental")] generate_extern_functions: bool, /// Sets the name of the header and source code files that would be created if any extern wrapper functions must be generated due to the presence of inlined functions. - #[arg(long, value_name = "FILENAME")] + #[arg(long, requires = "experimental", value_name = "FILENAME")] extern_functions_file_name: Option, - #[arg(long, value_name = "DIRECTORY")] + #[arg(long, requires = "experimental", value_name = "DIRECTORY")] /// Sets the directory path where any extra files must be created due to the presence of inlined functions. extern_functions_directory: Option, /// Sets the suffix added to the extern wrapper functions generated for inlined functions. - #[arg(long, value_name = "SUFFIX")] + #[arg(long, requires = "experimental", value_name = "SUFFIX")] extern_function_suffix: Option, + /// Enables experimental features. + #[arg(long)] + experimental: bool, /// Prints the version, and exits #[arg(short = 'V', long)] version: bool, @@ -489,6 +492,7 @@ where extern_functions_file_name, extern_functions_directory, extern_function_suffix, + experimental: _, version, clang_args, } = command; diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 9b97e84e45..9e5ce0c123 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -211,10 +211,13 @@ fn setup_extern_test() { let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); let out_rust_file = out_path.join("extern.rs"); - let input_header_dir = PathBuf::from("../bindgen-tests/tests/headers/").canonicalize() + let input_header_dir = PathBuf::from("../bindgen-tests/tests/headers/") + .canonicalize() .expect("Cannot canonicalize libdir path"); - let input_header_file_path = input_header_dir.join("generate-extern-functions.h"); - let input_header_file_path_str = input_header_file_path.to_str() + let input_header_file_path = + input_header_dir.join("generate-extern-functions.h"); + let input_header_file_path_str = input_header_file_path + .to_str() .expect("Path could not be converted to a str"); // generate external bindings with the external .c and .h files @@ -226,7 +229,7 @@ fn setup_extern_test() { .generate() .expect("Unable to generate bindings"); - println!("cargo:rustc-link-lib=extern"); // tell cargo to link libextern + println!("cargo:rustc-link-lib=extern"); // tell cargo to link libextern println!("bindings generated: {}", bindings); let obj_path = out_path.join("extern.o"); @@ -243,7 +246,8 @@ fn setup_extern_test() { .output() .expect("`clang` command error") .status - .success() { + .success() + { panic!("Could not compile object file"); } @@ -254,11 +258,13 @@ fn setup_extern_test() { .output() .expect("`ar` command error") .status - .success() { + .success() + { panic!("Could not emit library file"); } - bindings.write_to_file(out_rust_file) + bindings + .write_to_file(out_rust_file) .expect("Cound not write bindings to the Rust file"); } diff --git a/bindgen-tests/Cargo.toml b/bindgen-tests/Cargo.toml index 0678274fd6..6df84e8e9b 100644 --- a/bindgen-tests/Cargo.toml +++ b/bindgen-tests/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" publish = false [dev-dependencies] -bindgen = { path = "../bindgen", features = ["cli"] } +bindgen = { path = "../bindgen", features = ["cli", "experimental"] } diff = "0.1" shlex = "1" clap = { version = "4", features = ["derive"] } diff --git a/bindgen-tests/tests/headers/generate-extern-functions.h b/bindgen-tests/tests/headers/generate-extern-functions.h index e5b20f746f..6725226c5c 100644 --- a/bindgen-tests/tests/headers/generate-extern-functions.h +++ b/bindgen-tests/tests/headers/generate-extern-functions.h @@ -1,4 +1,4 @@ -// bindgen-flags: --generate-extern-functions +// bindgen-flags: --experimental --generate-extern-functions static inline int foo() { return 11; diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 16286b1299..d48dd7299c 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -749,7 +749,7 @@ fn test_extern_generated_headers() { None, Path::new(expect_path.join("extern.c").to_str().unwrap()), ) - .unwrap(); + .unwrap(); } if expected_h != actual_h { @@ -759,7 +759,6 @@ fn test_extern_generated_headers() { None, Path::new(expect_path.join("extern.h").to_str().unwrap()), ) - .unwrap(); + .unwrap(); } - -} \ No newline at end of file +} diff --git a/bindgen/Cargo.toml b/bindgen/Cargo.toml index 2292a5efe4..6d4902d452 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/lib.rs b/bindgen/lib.rs index 2c3210f981..7ba25a1366 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -677,6 +677,10 @@ impl Builder { output_vector.push(suffix.clone()); } + if cfg!(feature = "experimental") { + output_vector.push("--experimental".into()); + } + // Add clang arguments output_vector.push("--".into()); @@ -1815,6 +1819,7 @@ impl Builder { self } + #[cfg(feature = "experimental")] /// Whether to generate extern wrappers for inline functions. Defaults to false. pub fn generate_extern_functions(mut self, doit: bool) -> Self { self.options.generate_extern_functions = if doit { @@ -1825,6 +1830,7 @@ impl Builder { self } + #[cfg(feature = "experimental")] /// Set the name of the header and source code files that would be created if any extern /// wrapper functions must be generated due to the presence of inlined functions. pub fn extern_functions_file_name>( @@ -1836,6 +1842,7 @@ impl Builder { self } + #[cfg(feature = "experimental")] /// Set the directory path where any extra files must be created due to the presence of inlined /// functions. pub fn extern_functions_directory>( @@ -1847,6 +1854,7 @@ impl Builder { self } + #[cfg(feature = "experimental")] /// Set the suffix added to the extern wrapper functions generated for inlined functions. pub fn extern_function_suffix>(mut self, suffix: T) -> Self { self.options.extern_function_suffix = Some(suffix.as_ref().to_owned()); From 61b2b44c83b319de3ad2b251fc1e2b60be922062 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Jan 2023 12:14:10 -0500 Subject: [PATCH 04/37] Rename options --- bindgen-cli/options.rs | 36 ++++++++++++++++++------------------ bindgen-integration/build.rs | 4 ++-- bindgen-tests/tests/tests.rs | 4 ++-- bindgen/lib.rs | 8 ++++---- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index d6459b41e1..35ff43b8f4 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -355,16 +355,16 @@ struct BindgenCommand { with_derive_custom_union: Vec, /// Generate extern wrappers for inlined functions #[arg(long, requires = "experimental")] - generate_extern_functions: bool, + wrap_non_extern_fns: bool, /// Sets the name of the header and source code files that would be created if any extern wrapper functions must be generated due to the presence of inlined functions. #[arg(long, requires = "experimental", value_name = "FILENAME")] - extern_functions_file_name: Option, + non_extern_fns_filename: Option, #[arg(long, requires = "experimental", value_name = "DIRECTORY")] /// Sets the directory path where any extra files must be created due to the presence of inlined functions. - extern_functions_directory: Option, + non_extern_fns_directory: Option, /// Sets the suffix added to the extern wrapper functions generated for inlined functions. #[arg(long, requires = "experimental", value_name = "SUFFIX")] - extern_function_suffix: Option, + non_extern_fns_suffix: Option, /// Enables experimental features. #[arg(long)] experimental: bool, @@ -488,10 +488,10 @@ where with_derive_custom_struct, with_derive_custom_enum, with_derive_custom_union, - generate_extern_functions, - extern_functions_file_name, - extern_functions_directory, - extern_function_suffix, + wrap_non_extern_fns, + non_extern_fns_filename, + non_extern_fns_directory, + non_extern_fns_suffix, experimental: _, version, clang_args, @@ -965,8 +965,8 @@ where &self, info: &bindgen::callbacks::DeriveInfo<'_>, ) -> Vec { - if self.kind.map(|kind| kind == info.kind).unwrap_or(true) && - self.regex_set.matches(info.name) + if self.kind.map(|kind| kind == info.kind).unwrap_or(true) + && self.regex_set.matches(info.name) { return self.derives.clone(); } @@ -998,20 +998,20 @@ where } } - if generate_extern_functions { - builder = builder.generate_extern_functions(true); + if wrap_non_extern_fns { + builder = builder.wrap_non_extern_fns(true); } - if let Some(file_name) = extern_functions_file_name { - builder = builder.extern_functions_file_name(file_name); + if let Some(file_name) = non_extern_fns_filename { + builder = builder.non_extern_fns_filename(file_name); } - if let Some(directory) = extern_functions_directory { - builder = builder.extern_functions_directory(directory); + if let Some(directory) = non_extern_fns_directory { + builder = builder.non_extern_fns_directory(directory); } - if let Some(suffix) = extern_function_suffix { - builder = builder.extern_function_suffix(suffix); + if let Some(suffix) = non_extern_fns_suffix { + builder = builder.non_extern_fsn_suffix(suffix); } Ok((builder, output, verbose)) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 9e5ce0c123..58bc4998e9 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -224,8 +224,8 @@ fn setup_extern_test() { let bindings = Builder::default() .header(input_header_file_path_str) .parse_callbacks(Box::new(CargoCallbacks)) - .generate_extern_functions(true) - .extern_functions_directory(out_path.display().to_string()) + .wrap_non_extern_fns(true) + .non_extern_fns_directory(out_path.display().to_string()) .generate() .expect("Unable to generate bindings"); diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index d48dd7299c..017c02fe4e 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -727,8 +727,8 @@ fn test_extern_generated_headers() { let _bindings = Builder::default() .header("tests/headers/generate-extern-functions.h") - .generate_extern_functions(true) - .extern_functions_directory(generated_path.display().to_string()) + .wrap_non_extern_fns(true) + .non_extern_fns_directory(generated_path.display().to_string()) .generate() .expect("Failed to generate bindings"); diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 7ba25a1366..0eedee9efa 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -1821,7 +1821,7 @@ impl Builder { #[cfg(feature = "experimental")] /// Whether to generate extern wrappers for inline functions. Defaults to false. - pub fn generate_extern_functions(mut self, doit: bool) -> Self { + pub fn wrap_non_extern_fns(mut self, doit: bool) -> Self { self.options.generate_extern_functions = if doit { GenerateExternFunctions::True } else { @@ -1833,7 +1833,7 @@ impl Builder { #[cfg(feature = "experimental")] /// Set the name of the header and source code files that would be created if any extern /// wrapper functions must be generated due to the presence of inlined functions. - pub fn extern_functions_file_name>( + pub fn non_extern_fns_filename>( mut self, file_name: T, ) -> Self { @@ -1845,7 +1845,7 @@ impl Builder { #[cfg(feature = "experimental")] /// Set the directory path where any extra files must be created due to the presence of inlined /// functions. - pub fn extern_functions_directory>( + pub fn non_extern_fns_directory>( mut self, directory: T, ) -> Self { @@ -1856,7 +1856,7 @@ impl Builder { #[cfg(feature = "experimental")] /// Set the suffix added to the extern wrapper functions generated for inlined functions. - pub fn extern_function_suffix>(mut self, suffix: T) -> Self { + pub fn non_extern_fsn_suffix>(mut self, suffix: T) -> Self { self.options.extern_function_suffix = Some(suffix.as_ref().to_owned()); self } From 65a80e0be0d7dfbfad89c103a4848a9d3a116873 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Jan 2023 12:18:26 -0500 Subject: [PATCH 05/37] Fixup: Rename options --- bindgen-cli/options.rs | 4 +- bindgen-integration/build.rs | 3 +- .../expectations/tests/generated/README.md | 2 +- ...rn-functions.rs => wrap-non-extern-fns.rs} | 0 ...tern-functions.h => wrap-non-extern-fns.h} | 2 +- bindgen-tests/tests/tests.rs | 2 +- bindgen/codegen/mod.rs | 4 +- bindgen/ir/function.rs | 4 +- bindgen/ir/serialize.rs | 2 +- bindgen/lib.rs | 57 +++++++++---------- 10 files changed, 39 insertions(+), 41 deletions(-) rename bindgen-tests/tests/expectations/tests/{generate-extern-functions.rs => wrap-non-extern-fns.rs} (100%) rename bindgen-tests/tests/headers/{generate-extern-functions.h => wrap-non-extern-fns.h} (65%) diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index 35ff43b8f4..07df3da795 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -965,8 +965,8 @@ where &self, info: &bindgen::callbacks::DeriveInfo<'_>, ) -> Vec { - if self.kind.map(|kind| kind == info.kind).unwrap_or(true) - && self.regex_set.matches(info.name) + if self.kind.map(|kind| kind == info.kind).unwrap_or(true) && + self.regex_set.matches(info.name) { return self.derives.clone(); } diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 58bc4998e9..0f1e454533 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -214,8 +214,7 @@ fn setup_extern_test() { let input_header_dir = PathBuf::from("../bindgen-tests/tests/headers/") .canonicalize() .expect("Cannot canonicalize libdir path"); - let input_header_file_path = - input_header_dir.join("generate-extern-functions.h"); + let input_header_file_path = input_header_dir.join("wrap-non-extern-fns.h"); let input_header_file_path_str = input_header_file_path .to_str() .expect("Path could not be converted to a str"); diff --git a/bindgen-tests/tests/expectations/tests/generated/README.md b/bindgen-tests/tests/expectations/tests/generated/README.md index 7b9eea412c..ce7e0f1b28 100644 --- a/bindgen-tests/tests/expectations/tests/generated/README.md +++ b/bindgen-tests/tests/expectations/tests/generated/README.md @@ -1,4 +1,4 @@ # Generated C, C++, Header files This directory contains files for features where extra files are generated -as a part of the feature. For example, `--generated-extern-functions`. \ No newline at end of file +as a part of the feature. For example, `--wrap-non-extern-fns`. diff --git a/bindgen-tests/tests/expectations/tests/generate-extern-functions.rs b/bindgen-tests/tests/expectations/tests/wrap-non-extern-fns.rs similarity index 100% rename from bindgen-tests/tests/expectations/tests/generate-extern-functions.rs rename to bindgen-tests/tests/expectations/tests/wrap-non-extern-fns.rs diff --git a/bindgen-tests/tests/headers/generate-extern-functions.h b/bindgen-tests/tests/headers/wrap-non-extern-fns.h similarity index 65% rename from bindgen-tests/tests/headers/generate-extern-functions.h rename to bindgen-tests/tests/headers/wrap-non-extern-fns.h index 6725226c5c..58a70a02f1 100644 --- a/bindgen-tests/tests/headers/generate-extern-functions.h +++ b/bindgen-tests/tests/headers/wrap-non-extern-fns.h @@ -1,4 +1,4 @@ -// bindgen-flags: --experimental --generate-extern-functions +// bindgen-flags: --experimental --wrap-non-extern-fns static inline int foo() { return 11; diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 017c02fe4e..8643378f51 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -726,7 +726,7 @@ fn test_extern_generated_headers() { println!("Out path is ::: {}", generated_path.to_str().unwrap()); let _bindings = Builder::default() - .header("tests/headers/generate-extern-functions.h") + .header("tests/headers/wrap-non-extern-fns.h") .wrap_non_extern_fns(true) .non_extern_fns_directory(generated_path.display().to_string()) .generate() diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 309ccb65f0..829be33e98 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4134,10 +4134,10 @@ impl CodeGenerator for Function { quote! { #[link(wasm_import_module = #name)] } }); - if ctx.options().generate_extern_functions.is_second_run() { + if ctx.options().wrap_non_extern_fns.is_second_run() { if let Some(name) = canonical_name.strip_suffix( ctx.options() - .extern_function_suffix + .non_extern_fns_suffix .as_deref() .unwrap_or(crate::DEFAULT_EXTERN_FUNCTION_SUFFIX), ) { diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 8d976950e3..42b59199f3 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -681,7 +681,7 @@ impl ClangSubItemParser for Function { .map_or(false, |x| x.is_inlined_function()) { if !(context.options().generate_inline_functions || - context.options().generate_extern_functions.is_true()) + context.options().wrap_non_extern_fns.is_true()) { return Err(ParseError::Continue); } @@ -734,7 +734,7 @@ impl ClangSubItemParser for Function { Self::new(name, mangled_name, sig, comment, kind, linkage); if matches!(linkage, Linkage::Internal) && - context.options().generate_extern_functions.is_true() + context.options().wrap_non_extern_fns.is_true() { match CItem::from_function(&function, context) { Ok(c_item) => context.c_items.push(c_item), diff --git a/bindgen/ir/serialize.rs b/bindgen/ir/serialize.rs index bc480acaa5..cebef53969 100644 --- a/bindgen/ir/serialize.rs +++ b/bindgen/ir/serialize.rs @@ -68,7 +68,7 @@ impl CItem { " {}{}(", name, ctx.options() - .extern_function_suffix + .non_extern_fns_suffix .as_deref() .unwrap_or(DEFAULT_EXTERN_FUNCTION_SUFFIX) )?; diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 0eedee9efa..32594a6a95 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -658,22 +658,22 @@ impl Builder { for callbacks in &self.options.parse_callbacks { output_vector.extend(callbacks.cli_args()); } - if self.options.generate_extern_functions.is_true() { - output_vector.push("--generate-extern-functions".into()) + if self.options.wrap_non_extern_fns.is_true() { + output_vector.push("--wrap-non-extern-fns".into()) } - if let Some(ref file_name) = self.options.extern_functions_file_name { - output_vector.push("--extern-functions-file-name".into()); + if let Some(ref file_name) = self.options.non_extern_fns_filename { + output_vector.push("--non-extern-fns-filename".into()); output_vector.push(file_name.clone()); } - if let Some(ref directory) = self.options.extern_functions_directory { - output_vector.push("--extern-functions-directory".into()); + if let Some(ref directory) = self.options.non_extern_fns_directory { + output_vector.push("--non-extern-fns-directory".into()); output_vector.push(directory.display().to_string()); } - if let Some(ref suffix) = self.options.extern_function_suffix { - output_vector.push("--extern-function-suffix".into()); + if let Some(ref suffix) = self.options.non_extern_fns_suffix { + output_vector.push("--non-extern-fns-suffix".into()); output_vector.push(suffix.clone()); } @@ -1822,10 +1822,10 @@ impl Builder { #[cfg(feature = "experimental")] /// Whether to generate extern wrappers for inline functions. Defaults to false. pub fn wrap_non_extern_fns(mut self, doit: bool) -> Self { - self.options.generate_extern_functions = if doit { - GenerateExternFunctions::True + self.options.wrap_non_extern_fns = if doit { + WrapNonExternFns::True } else { - GenerateExternFunctions::False + WrapNonExternFns::False }; self } @@ -1837,7 +1837,7 @@ impl Builder { mut self, file_name: T, ) -> Self { - self.options.extern_functions_file_name = + self.options.non_extern_fns_filename = Some(file_name.as_ref().to_owned()); self } @@ -1849,7 +1849,7 @@ impl Builder { mut self, directory: T, ) -> Self { - self.options.extern_functions_directory = + self.options.non_extern_fns_directory = Some(directory.as_ref().to_owned().into()); self } @@ -1857,25 +1857,24 @@ impl Builder { #[cfg(feature = "experimental")] /// Set the suffix added to the extern wrapper functions generated for inlined functions. pub fn non_extern_fsn_suffix>(mut self, suffix: T) -> Self { - self.options.extern_function_suffix = Some(suffix.as_ref().to_owned()); + self.options.non_extern_fns_suffix = Some(suffix.as_ref().to_owned()); self } fn second_run(mut self, extra_header: String) -> Self { - self.options.generate_extern_functions = - GenerateExternFunctions::SecondRun; + self.options.wrap_non_extern_fns = WrapNonExternFns::SecondRun; self.header(extra_header) } } #[derive(Clone, Copy, Debug)] -enum GenerateExternFunctions { +enum WrapNonExternFns { True, False, SecondRun, } -impl GenerateExternFunctions { +impl WrapNonExternFns { fn is_true(self) -> bool { matches!(self, Self::True) } @@ -1885,7 +1884,7 @@ impl GenerateExternFunctions { } } -impl Default for GenerateExternFunctions { +impl Default for WrapNonExternFns { fn default() -> Self { Self::False } @@ -2230,13 +2229,13 @@ struct BindgenOptions { /// Whether to wrap unsafe operations in unsafe blocks or not. wrap_unsafe_ops: bool, - generate_extern_functions: GenerateExternFunctions, + wrap_non_extern_fns: WrapNonExternFns, - extern_function_suffix: Option, + non_extern_fns_suffix: Option, - extern_functions_directory: Option, + non_extern_fns_directory: Option, - extern_functions_file_name: Option, + non_extern_fns_filename: Option, } impl BindgenOptions { @@ -2429,10 +2428,10 @@ impl Default for BindgenOptions { merge_extern_blocks, abi_overrides, wrap_unsafe_ops, - generate_extern_functions, - extern_function_suffix, - extern_functions_directory, - extern_functions_file_name, + wrap_non_extern_fns, + non_extern_fns_suffix, + non_extern_fns_directory, + non_extern_fns_filename, } } } @@ -2740,7 +2739,7 @@ impl Bindings { ) -> Result { let dir = context .options() - .extern_functions_directory + .non_extern_fns_directory .clone() .unwrap_or_else(|| std::env::temp_dir().join("bindgen")); @@ -2751,7 +2750,7 @@ impl Bindings { let path = std::fs::canonicalize(dir)?.join( context .options() - .extern_functions_file_name + .non_extern_fns_filename .as_deref() .unwrap_or("extern"), ); From eb823b86fc7bcfac9e5f007dd7272ad8d4c86864 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Jan 2023 13:37:07 -0500 Subject: [PATCH 06/37] merge filename and directory arguments --- bindgen-cli/options.rs | 28 +++++-------- bindgen-tests/tests/tests.rs | 24 ++++++----- bindgen/codegen/mod.rs | 4 +- bindgen/ir/serialize.rs | 6 +-- bindgen/lib.rs | 81 +++++++++++++----------------------- 5 files changed, 58 insertions(+), 85 deletions(-) diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index 07df3da795..3984bf68b0 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -356,15 +356,12 @@ struct BindgenCommand { /// Generate extern wrappers for inlined functions #[arg(long, requires = "experimental")] wrap_non_extern_fns: bool, - /// Sets the name of the header and source code files that would be created if any extern wrapper functions must be generated due to the presence of inlined functions. - #[arg(long, requires = "experimental", value_name = "FILENAME")] - non_extern_fns_filename: Option, - #[arg(long, requires = "experimental", value_name = "DIRECTORY")] - /// Sets the directory path where any extra files must be created due to the presence of inlined functions. - non_extern_fns_directory: Option, + /// Sets the path for any extra files must be created due to the presence of inlined functions. + #[arg(long, requires = "experimental", value_name = "PATH")] + wrap_non_extern_fns_path: Option, /// Sets the suffix added to the extern wrapper functions generated for inlined functions. #[arg(long, requires = "experimental", value_name = "SUFFIX")] - non_extern_fns_suffix: Option, + wrap_non_extern_fns_suffix: Option, /// Enables experimental features. #[arg(long)] experimental: bool, @@ -489,9 +486,8 @@ where with_derive_custom_enum, with_derive_custom_union, wrap_non_extern_fns, - non_extern_fns_filename, - non_extern_fns_directory, - non_extern_fns_suffix, + wrap_non_extern_fns_path, + wrap_non_extern_fns_suffix, experimental: _, version, clang_args, @@ -1002,16 +998,12 @@ where builder = builder.wrap_non_extern_fns(true); } - if let Some(file_name) = non_extern_fns_filename { - builder = builder.non_extern_fns_filename(file_name); + if let Some(path) = wrap_non_extern_fns_path { + builder = builder.wrap_non_extern_fns_path(path); } - if let Some(directory) = non_extern_fns_directory { - builder = builder.non_extern_fns_directory(directory); - } - - if let Some(suffix) = non_extern_fns_suffix { - builder = builder.non_extern_fsn_suffix(suffix); + if let Some(suffix) = wrap_non_extern_fns_suffix { + builder = builder.wrap_non_extern_fns_suffix(suffix); } Ok((builder, output, verbose)) diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 8643378f51..543a047700 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -719,27 +719,29 @@ fn test_extern_generated_headers() { // This test is for testing diffs of the generated C source and header files // TODO: If another such feature is added, convert this test into a more generic // test that looks at `tests/headers/generated` directory. - let expect_path = PathBuf::from("tests/expectations/tests/generated"); - println!("In path is ::: {}", expect_path.to_str().unwrap()); + let expect_path = + PathBuf::from("tests/expectations/tests/generated").join("extern"); + println!("In path is ::: {}", expect_path.display()); - let generated_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - println!("Out path is ::: {}", generated_path.to_str().unwrap()); + let generated_path = + PathBuf::from(env::var("OUT_DIR").unwrap()).join("extern"); + println!("Out path is ::: {}", generated_path.display()); let _bindings = Builder::default() .header("tests/headers/wrap-non-extern-fns.h") .wrap_non_extern_fns(true) - .non_extern_fns_directory(generated_path.display().to_string()) + .wrap_non_extern_fns_path(generated_path.display().to_string()) .generate() .expect("Failed to generate bindings"); - let expected_c = fs::read_to_string(expect_path.join("extern.c")) + let expected_c = fs::read_to_string(expect_path.with_extension("c")) .expect("Could not read generated extern.c"); - let expected_h = fs::read_to_string(expect_path.join("extern.h")) + let expected_h = fs::read_to_string(expect_path.with_extension("h")) .expect("Could not read generated extern.h"); - let actual_c = fs::read_to_string(generated_path.join("extern.c")) + let actual_c = fs::read_to_string(generated_path.with_extension("c")) .expect("Could not read actual extern.c"); - let actual_h = fs::read_to_string(generated_path.join("extern.h")) + let actual_h = fs::read_to_string(generated_path.with_extension("h")) .expect("Could not read actual extern.h"); if expected_c != actual_c { @@ -747,7 +749,7 @@ fn test_extern_generated_headers() { &actual_c, &expected_c, None, - Path::new(expect_path.join("extern.c").to_str().unwrap()), + &expect_path.with_extension("c"), ) .unwrap(); } @@ -757,7 +759,7 @@ fn test_extern_generated_headers() { &actual_h, &expected_h, None, - Path::new(expect_path.join("extern.h").to_str().unwrap()), + &expect_path.with_extension("h"), ) .unwrap(); } diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 829be33e98..5c75095d25 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4137,9 +4137,9 @@ impl CodeGenerator for Function { if ctx.options().wrap_non_extern_fns.is_second_run() { if let Some(name) = canonical_name.strip_suffix( ctx.options() - .non_extern_fns_suffix + .wrap_non_extern_fns_suffix .as_deref() - .unwrap_or(crate::DEFAULT_EXTERN_FUNCTION_SUFFIX), + .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX), ) { if !has_link_name_attr { attributes.push(attributes::link_name(&canonical_name)); diff --git a/bindgen/ir/serialize.rs b/bindgen/ir/serialize.rs index cebef53969..91d95752bb 100644 --- a/bindgen/ir/serialize.rs +++ b/bindgen/ir/serialize.rs @@ -1,7 +1,7 @@ use std::fmt::{self, Write}; use crate::callbacks::IntKind; -use crate::DEFAULT_EXTERN_FUNCTION_SUFFIX; +use crate::DEFAULT_NON_EXTERN_FNS_SUFFIX; use super::context::{BindgenContext, TypeId}; use super::function::{Function, FunctionKind}; @@ -68,9 +68,9 @@ impl CItem { " {}{}(", name, ctx.options() - .non_extern_fns_suffix + .wrap_non_extern_fns_suffix .as_deref() - .unwrap_or(DEFAULT_EXTERN_FUNCTION_SUFFIX) + .unwrap_or(DEFAULT_NON_EXTERN_FNS_SUFFIX) )?; serialize_sep( ", ", diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 32594a6a95..fd8fb4e853 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -108,7 +108,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_EXTERN_FUNCTION_SUFFIX: &str = "__extern"; +const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern"; fn file_is_cpp(name_file: &str) -> bool { name_file.ends_with(".hpp") || @@ -662,18 +662,13 @@ impl Builder { output_vector.push("--wrap-non-extern-fns".into()) } - if let Some(ref file_name) = self.options.non_extern_fns_filename { - output_vector.push("--non-extern-fns-filename".into()); - output_vector.push(file_name.clone()); + if let Some(ref path) = self.options.wrap_non_extern_fns_path { + output_vector.push("--wrap-non-extern-fns-path".into()); + output_vector.push(path.to_string()); } - if let Some(ref directory) = self.options.non_extern_fns_directory { - output_vector.push("--non-extern-fns-directory".into()); - output_vector.push(directory.display().to_string()); - } - - if let Some(ref suffix) = self.options.non_extern_fns_suffix { - output_vector.push("--non-extern-fns-suffix".into()); + if let Some(ref suffix) = self.options.wrap_non_extern_fns_suffix { + output_vector.push("--wrap-non-extern-fns-suffix".into()); output_vector.push(suffix.clone()); } @@ -1831,33 +1826,23 @@ impl Builder { } #[cfg(feature = "experimental")] - /// Set the name of the header and source code files that would be created if any extern - /// wrapper functions must be generated due to the presence of inlined functions. - pub fn non_extern_fns_filename>( - mut self, - file_name: T, - ) -> Self { - self.options.non_extern_fns_filename = - Some(file_name.as_ref().to_owned()); + /// Set the path of the header and source code files that would be created if any extern + /// wrapper functions must be generated due to the presence of non-extern functions. + /// + /// Bindgen will automatically add the right extension to the header and source code files. + pub fn wrap_non_extern_fns_path>(mut self, path: T) -> Self { + self.options.wrap_non_extern_fns_path = Some(path.as_ref().to_owned()); self } #[cfg(feature = "experimental")] - /// Set the directory path where any extra files must be created due to the presence of inlined - /// functions. - pub fn non_extern_fns_directory>( + /// Set the suffix added to the extern wrapper functions generated for inlined functions. + pub fn wrap_non_extern_fns_suffix>( mut self, - directory: T, + suffix: T, ) -> Self { - self.options.non_extern_fns_directory = - Some(directory.as_ref().to_owned().into()); - self - } - - #[cfg(feature = "experimental")] - /// Set the suffix added to the extern wrapper functions generated for inlined functions. - pub fn non_extern_fsn_suffix>(mut self, suffix: T) -> Self { - self.options.non_extern_fns_suffix = Some(suffix.as_ref().to_owned()); + self.options.wrap_non_extern_fns_suffix = + Some(suffix.as_ref().to_owned()); self } @@ -2231,11 +2216,9 @@ struct BindgenOptions { wrap_non_extern_fns: WrapNonExternFns, - non_extern_fns_suffix: Option, + wrap_non_extern_fns_suffix: Option, - non_extern_fns_directory: Option, - - non_extern_fns_filename: Option, + wrap_non_extern_fns_path: Option, } impl BindgenOptions { @@ -2429,9 +2412,8 @@ impl Default for BindgenOptions { abi_overrides, wrap_unsafe_ops, wrap_non_extern_fns, - non_extern_fns_suffix, - non_extern_fns_directory, - non_extern_fns_filename, + wrap_non_extern_fns_suffix, + wrap_non_extern_fns_path, } } } @@ -2737,24 +2719,21 @@ impl Bindings { fn serialize_c_items( context: &BindgenContext, ) -> Result { - let dir = context + let path = context .options() - .non_extern_fns_directory - .clone() - .unwrap_or_else(|| std::env::temp_dir().join("bindgen")); + .wrap_non_extern_fns_path + .as_ref() + .map(|path| PathBuf::from(path)) + .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 path = std::fs::canonicalize(dir)?.join( - context - .options() - .non_extern_fns_filename - .as_deref() - .unwrap_or("extern"), - ); - let is_cpp = args_are_cpp(&context.options().clang_args) || context .options() From 8b0bdcdb5089febe879e38e9342df7d9380a5719 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Jan 2023 15:34:40 -0500 Subject: [PATCH 07/37] avoid second run --- bindgen/codegen/mod.rs | 21 ++++----- bindgen/ir/function.rs | 49 ++++++++++++++----- bindgen/lib.rs | 104 +++++++++-------------------------------- 3 files changed, 69 insertions(+), 105 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 5c75095d25..c1cbd207c5 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4000,9 +4000,10 @@ impl CodeGenerator for Function { debug!("::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. - if matches!(self.linkage(), Linkage::Internal) { + let is_internal = matches!(self.linkage(), Linkage::Internal); + // We can't do anything with Internal functions if we are not wrapping them so just avoid + // generating anything for them. + if is_internal && !ctx.options().wrap_non_extern_fns { return None; } @@ -4134,17 +4135,15 @@ impl CodeGenerator for Function { quote! { #[link(wasm_import_module = #name)] } }); - if ctx.options().wrap_non_extern_fns.is_second_run() { - if let Some(name) = canonical_name.strip_suffix( + if is_internal && ctx.options().wrap_non_extern_fns { + let name = canonical_name.clone() + ctx.options() .wrap_non_extern_fns_suffix .as_deref() - .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX), - ) { - if !has_link_name_attr { - attributes.push(attributes::link_name(&canonical_name)); - } - canonical_name = name.to_owned(); + .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX); + + if !has_link_name_attr { + attributes.push(attributes::link_name(&name)); } } diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 42b59199f3..5197147878 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -95,6 +95,9 @@ pub struct Function { /// The linkage of the function. linkage: Linkage, + + /// Is this function inlined?. + is_inlined_function: bool, } impl Function { @@ -106,6 +109,7 @@ impl Function { comment: Option, kind: FunctionKind, linkage: Linkage, + is_inlined_function: bool, ) -> Self { Function { name, @@ -114,6 +118,7 @@ impl Function { comment, kind, linkage, + is_inlined_function, } } @@ -146,6 +151,11 @@ impl Function { pub fn linkage(&self) -> Linkage { self.linkage } + + /// Is this function inlined? + pub fn is_inlined_function(&self) -> bool { + self.is_inlined_function + } } impl DotAttributes for Function { @@ -665,7 +675,6 @@ impl ClangSubItemParser for Function { }; debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type()); - let visibility = cursor.visibility(); if visibility != CXVisibility_Default { return Err(ParseError::Continue); @@ -675,13 +684,20 @@ 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 || - context.options().wrap_non_extern_fns.is_true()) + context.options().wrap_non_extern_fns) { return Err(ParseError::Continue); } @@ -689,14 +705,14 @@ impl ClangSubItemParser for Function { 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), - }; + if context.options().wrap_non_extern_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)?; @@ -730,11 +746,18 @@ impl ClangSubItemParser for Function { let mangled_name = cursor_mangling(context, &cursor); let comment = cursor.raw_comment(); - let function = - Self::new(name, mangled_name, sig, comment, kind, linkage); + let function = Self::new( + name.clone(), + mangled_name, + sig, + comment, + kind, + linkage, + cursor.is_inlined_function(), + ); if matches!(linkage, Linkage::Internal) && - context.options().wrap_non_extern_fns.is_true() + context.options().wrap_non_extern_fns { match CItem::from_function(&function, context) { Ok(c_item) => context.c_items.push(c_item), @@ -742,6 +765,8 @@ impl ClangSubItemParser for Function { } } + dbg!(("done parsing", name)); + Ok(ParseResult::New(function, Some(cursor))) } } diff --git a/bindgen/lib.rs b/bindgen/lib.rs index fd8fb4e853..fffa90ffc2 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -658,7 +658,7 @@ impl Builder { for callbacks in &self.options.parse_callbacks { output_vector.extend(callbacks.cli_args()); } - if self.options.wrap_non_extern_fns.is_true() { + if self.options.wrap_non_extern_fns { output_vector.push("--wrap-non-extern-fns".into()) } @@ -1571,32 +1571,25 @@ impl Builder { } /// Generate the Rust bindings using the options built up thus far. - pub fn generate(self) -> Result { - let mut options = self.options.clone(); + pub fn generate(mut self) -> Result { // 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::>(); - match Bindings::generate(options, input_unsaved_files) { - GenerateResult::Ok(bindings) => Ok(*bindings), - GenerateResult::ShouldRestart { header } => { - self.second_run(header).generate() - } - GenerateResult::Err(err) => Err(err), - } + Bindings::generate(self.options, input_unsaved_files) } /// Preprocess and dump the input header files to disk. @@ -1817,11 +1810,7 @@ impl Builder { #[cfg(feature = "experimental")] /// Whether to generate extern wrappers for inline functions. Defaults to false. pub fn wrap_non_extern_fns(mut self, doit: bool) -> Self { - self.options.wrap_non_extern_fns = if doit { - WrapNonExternFns::True - } else { - WrapNonExternFns::False - }; + self.options.wrap_non_extern_fns = doit; self } @@ -1845,34 +1834,6 @@ impl Builder { Some(suffix.as_ref().to_owned()); self } - - fn second_run(mut self, extra_header: String) -> Self { - self.options.wrap_non_extern_fns = WrapNonExternFns::SecondRun; - self.header(extra_header) - } -} - -#[derive(Clone, Copy, Debug)] -enum WrapNonExternFns { - True, - False, - SecondRun, -} - -impl WrapNonExternFns { - fn is_true(self) -> bool { - matches!(self, Self::True) - } - - fn is_second_run(self) -> bool { - matches!(self, Self::SecondRun) - } -} - -impl Default for WrapNonExternFns { - fn default() -> Self { - Self::False - } } /// Configuration options for generated bindings. @@ -2214,7 +2175,7 @@ struct BindgenOptions { /// Whether to wrap unsafe operations in unsafe blocks or not. wrap_unsafe_ops: bool, - wrap_non_extern_fns: WrapNonExternFns, + wrap_non_extern_fns: bool, wrap_non_extern_fns_suffix: Option, @@ -2444,17 +2405,6 @@ fn ensure_libclang_is_loaded() { #[cfg(not(feature = "runtime"))] fn ensure_libclang_is_loaded() {} -#[derive(Debug)] -enum GenerateResult { - Ok(Box), - /// Error variant raised when bindgen requires to run again with a newly generated header - /// input. - ShouldRestart { - header: String, - }, - Err(BindgenError), -} - /// Error type for rust-bindgen. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] @@ -2548,7 +2498,7 @@ impl Bindings { pub(crate) fn generate( mut options: BindgenOptions, input_unsaved_files: Vec, - ) -> GenerateResult { + ) -> Result { ensure_libclang_is_loaded(); #[cfg(feature = "runtime")] @@ -2669,21 +2619,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())); } } @@ -2711,14 +2657,12 @@ 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)?; } fn serialize_c_items( context: &BindgenContext, - ) -> Result { + ) -> Result<(), std::io::Error> { let path = context .options() .wrap_non_extern_fns_path @@ -2754,27 +2698,23 @@ impl Bindings { writeln!(source_file, "{}", item.code())?; } - Ok(headers_path) + Ok(()) } if !context.c_items.is_empty() { match serialize_c_items(&context) { - Ok(headers) => { - return GenerateResult::ShouldRestart { - header: headers.display().to_string(), - } - } + Ok(()) => (), Err(err) => warn!("Could not serialize C items: {}", err), } } let (module, options, warnings) = codegen::codegen(context); - GenerateResult::Ok(Box::new(Bindings { + Ok(Bindings { options, warnings, module, - })) + }) } /// Write these bindings as source text to a file. From 39ac21b8dc9e06b163d0f7efea787d4f410a79c4 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Jan 2023 15:56:46 -0500 Subject: [PATCH 08/37] move all c serialization to codegen --- bindgen/codegen/mod.rs | 75 ++++++++++++++++++++++++++-- bindgen/{ir => codegen}/serialize.rs | 6 +-- bindgen/ir/context.rs | 5 -- bindgen/ir/function.rs | 10 ---- bindgen/ir/mod.rs | 1 - bindgen/lib.rs | 48 ------------------ 6 files changed, 73 insertions(+), 72 deletions(-) rename bindgen/{ir => codegen}/serialize.rs (98%) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index c1cbd207c5..c967e9177c 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)] @@ -46,6 +47,7 @@ use crate::ir::template::{ }; use crate::ir::ty::{Type, TypeKind}; use crate::ir::var::Var; +use serialize::CItem; use proc_macro2::{self, Ident, Span}; use quote::TokenStreamExt; @@ -241,6 +243,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, + + c_items: Vec, } impl<'a> CodegenResult<'a> { @@ -258,6 +262,7 @@ impl<'a> CodegenResult<'a> { functions_seen: Default::default(), vars_seen: Default::default(), overload_counters: Default::default(), + c_items: Default::default(), } } @@ -4001,10 +4006,18 @@ impl CodeGenerator for Function { debug_assert!(item.is_enabled_for_codegen(ctx)); let is_internal = matches!(self.linkage(), Linkage::Internal); - // We can't do anything with Internal functions if we are not wrapping them so just avoid - // generating anything for them. - if is_internal && !ctx.options().wrap_non_extern_fns { - return None; + + if is_internal { + if ctx.options().wrap_non_extern_fns { + match CItem::from_function(&self, ctx) { + Ok(c_item) => result.c_items.push(c_item), + Err(err) => warn!("Serialization failed: {:?}", err), + } + } 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 @@ -4501,21 +4514,73 @@ pub(crate) fn codegen( result.push(dynamic_items_tokens); } + if !result.c_items.is_empty() { + match utils::serialize_c_items(&result, &context) { + Ok(()) => (), + Err(err) => warn!("Could not serialize C items: {}", err), + } + } + postprocessing::postprocessing(result.items, context.options()) }) } pub mod utils { - use super::{error, ToRustTyOrOpaque}; + use super::{error, 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::fs::File; + use std::io::Write; use std::mem; + use std::path::PathBuf; use std::str::FromStr; + pub(super) fn serialize_c_items( + result: &CodegenResult, + context: &BindgenContext, + ) -> Result<(), std::io::Error> { + let path = context + .options() + .wrap_non_extern_fns_path + .as_ref() + .map(|path| PathBuf::from(path)) + .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 headers_path = + path.with_extension(if is_cpp { "hpp" } else { "h" }); + let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" }); + + let mut headers_file = File::create(&headers_path)?; + let mut source_file = File::create(source_path)?; + + for item in &result.c_items { + writeln!(headers_file, "{}", item.header())?; + writeln!(source_file, "{}", item.code())?; + } + + Ok(()) + } + pub fn prepend_bitfield_unit_type( ctx: &BindgenContext, result: &mut Vec, diff --git a/bindgen/ir/serialize.rs b/bindgen/codegen/serialize.rs similarity index 98% rename from bindgen/ir/serialize.rs rename to bindgen/codegen/serialize.rs index 91d95752bb..fa0e390cee 100644 --- a/bindgen/ir/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -3,9 +3,9 @@ use std::fmt::{self, Write}; use crate::callbacks::IntKind; use crate::DEFAULT_NON_EXTERN_FNS_SUFFIX; -use super::context::{BindgenContext, TypeId}; -use super::function::{Function, FunctionKind}; -use super::ty::{FloatKind, TypeKind}; +use crate::ir::context::{BindgenContext, TypeId}; +use crate::ir::function::{Function, FunctionKind}; +use crate::ir::ty::{FloatKind, TypeKind}; #[derive(Debug)] pub(crate) enum Error { diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index f82237f25d..c5df37d7e9 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -16,7 +16,6 @@ use super::int::IntKind; use super::item::{IsOpaque, Item, ItemAncestors, ItemSet}; use super::item_kind::ItemKind; use super::module::{Module, ModuleKind}; -use super::serialize::CItem; use super::template::{TemplateInstantiation, TemplateParameters}; use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, Type, TypeKind}; @@ -478,9 +477,6 @@ pub struct BindgenContext { /// The set of warnings raised during binding generation. warnings: Vec, - - /// C items that need to be serialized to an extra header file. - pub(crate) c_items: Vec, } /// A traversal of allowlisted items. @@ -597,7 +593,6 @@ If you encounter an error missing from this list, please file an issue or a PR!" has_type_param_in_array: None, has_float: None, warnings: Vec::new(), - c_items: Vec::new(), } } diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 5197147878..8cef444e46 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -8,7 +8,6 @@ use super::traversal::{EdgeKind, Trace, Tracer}; use super::ty::TypeKind; use crate::callbacks::{ItemInfo, ItemKind}; use crate::clang::{self, Attribute}; -use crate::ir::serialize::CItem; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; use clang_sys::{self, CXCallingConv}; use proc_macro2; @@ -756,15 +755,6 @@ impl ClangSubItemParser for Function { cursor.is_inlined_function(), ); - if matches!(linkage, Linkage::Internal) && - context.options().wrap_non_extern_fns - { - match CItem::from_function(&function, context) { - Ok(c_item) => context.c_items.push(c_item), - Err(err) => warn!("Serialization failed: {:?}", err), - } - } - dbg!(("done parsing", name)); Ok(ParseResult::New(function, Some(cursor))) diff --git a/bindgen/ir/mod.rs b/bindgen/ir/mod.rs index bb76e2ab4b..8f6a2dac88 100644 --- a/bindgen/ir/mod.rs +++ b/bindgen/ir/mod.rs @@ -18,7 +18,6 @@ pub mod item_kind; pub mod layout; pub mod module; pub mod objc; -pub(crate) mod serialize; pub mod template; pub mod traversal; pub mod ty; diff --git a/bindgen/lib.rs b/bindgen/lib.rs index fffa90ffc2..1759211df1 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -2660,54 +2660,6 @@ impl Bindings { parse(&mut context)?; } - fn serialize_c_items( - context: &BindgenContext, - ) -> Result<(), std::io::Error> { - let path = context - .options() - .wrap_non_extern_fns_path - .as_ref() - .map(|path| PathBuf::from(path)) - .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 headers_path = - path.with_extension(if is_cpp { "hpp" } else { "h" }); - let source_path = - path.with_extension(if is_cpp { "cpp" } else { "c" }); - - let mut headers_file = File::create(&headers_path)?; - let mut source_file = File::create(source_path)?; - - for item in &context.c_items { - writeln!(headers_file, "{}", item.header())?; - writeln!(source_file, "{}", item.code())?; - } - - Ok(()) - } - - if !context.c_items.is_empty() { - match serialize_c_items(&context) { - Ok(()) => (), - Err(err) => warn!("Could not serialize C items: {}", err), - } - } - let (module, options, warnings) = codegen::codegen(context); Ok(Bindings { From fa47c2b9b5cd8a0f012d6111cc8cf470882dc959 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Jan 2023 12:51:59 -0500 Subject: [PATCH 09/37] some nits --- bindgen-cli/options.rs | 2 +- bindgen/codegen/mod.rs | 18 ++++++++---------- bindgen/ir/context.rs | 7 +++++++ bindgen/ir/function.rs | 6 ++---- bindgen/lib.rs | 6 +++--- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index 3984bf68b0..d480f78bab 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -358,7 +358,7 @@ struct BindgenCommand { wrap_non_extern_fns: bool, /// Sets the path for any extra files must be created due to the presence of inlined functions. #[arg(long, requires = "experimental", value_name = "PATH")] - wrap_non_extern_fns_path: Option, + wrap_non_extern_fns_path: Option, /// Sets the suffix added to the extern wrapper functions generated for inlined functions. #[arg(long, requires = "experimental", value_name = "SUFFIX")] wrap_non_extern_fns_suffix: Option, diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index c967e9177c..e0cfe3817b 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4009,7 +4009,7 @@ impl CodeGenerator for Function { if is_internal { if ctx.options().wrap_non_extern_fns { - match CItem::from_function(&self, ctx) { + match CItem::from_function(self, ctx) { Ok(c_item) => result.c_items.push(c_item), Err(err) => warn!("Serialization failed: {:?}", err), } @@ -4148,16 +4148,14 @@ impl CodeGenerator for Function { quote! { #[link(wasm_import_module = #name)] } }); - if is_internal && ctx.options().wrap_non_extern_fns { - let name = canonical_name.clone() + - ctx.options() - .wrap_non_extern_fns_suffix - .as_deref() - .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX); + if is_internal && + ctx.options().wrap_non_extern_fns && + !has_link_name_attr + { + let name = + canonical_name.clone() + ctx.wrap_non_extern_fns_suffix(); - if !has_link_name_attr { - attributes.push(attributes::link_name(&name)); - } + attributes.push(attributes::link_name(&name)); } let ident = ctx.rust_ident(canonical_name); diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index c5df37d7e9..06752699fd 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -2792,6 +2792,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_non_extern_fns_suffix(&self) -> &str { + self.options() + .wrap_non_extern_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 8cef444e46..3074fa97bf 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -695,8 +695,8 @@ impl ClangSubItemParser for Function { .definition() .map_or(false, |x| x.is_inlined_function()) { - if !(context.options().generate_inline_functions || - context.options().wrap_non_extern_fns) + if !context.options().generate_inline_functions && + !context.options().wrap_non_extern_fns { return Err(ParseError::Continue); } @@ -755,8 +755,6 @@ impl ClangSubItemParser for Function { cursor.is_inlined_function(), ); - dbg!(("done parsing", name)); - Ok(ParseResult::New(function, Some(cursor))) } } diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 1759211df1..b8e4d46a89 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -664,7 +664,7 @@ impl Builder { if let Some(ref path) = self.options.wrap_non_extern_fns_path { output_vector.push("--wrap-non-extern-fns-path".into()); - output_vector.push(path.to_string()); + output_vector.push(path.display().to_string()); } if let Some(ref suffix) = self.options.wrap_non_extern_fns_suffix { @@ -1819,7 +1819,7 @@ impl Builder { /// wrapper functions must be generated due to the presence of non-extern functions. /// /// Bindgen will automatically add the right extension to the header and source code files. - pub fn wrap_non_extern_fns_path>(mut self, path: T) -> Self { + pub fn wrap_non_extern_fns_path>(mut self, path: T) -> Self { self.options.wrap_non_extern_fns_path = Some(path.as_ref().to_owned()); self } @@ -2179,7 +2179,7 @@ struct BindgenOptions { wrap_non_extern_fns_suffix: Option, - wrap_non_extern_fns_path: Option, + wrap_non_extern_fns_path: Option, } impl BindgenOptions { From e33237b0c375a5c164a7a1f62620fcf58ee6511e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Jan 2023 13:40:07 -0500 Subject: [PATCH 10/37] update docs and remove headers --- bindgen-cli/options.rs | 8 +++++--- bindgen/codegen/mod.rs | 4 ---- bindgen/codegen/serialize.rs | 29 ++++++++++++----------------- bindgen/lib.rs | 10 ++++++---- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index d480f78bab..2d2645f576 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -353,13 +353,15 @@ struct BindgenCommand { /// Derive custom traits on a `union`. The value must be of the shape = where is a coma-separated list of derive macros. #[arg(long, value_name = "CUSTOM")] with_derive_custom_union: Vec, - /// Generate extern wrappers for inlined functions + /// Generate wrappers for `static` and `static inline` functions. #[arg(long, requires = "experimental")] wrap_non_extern_fns: bool, - /// Sets the path for any extra files must be created due to the presence of inlined functions. + /// Sets the path for the source file that must be created due to the presence of `static` and + /// `static inline` functions. #[arg(long, requires = "experimental", value_name = "PATH")] wrap_non_extern_fns_path: Option, - /// Sets the suffix added to the extern wrapper functions generated for inlined functions. + /// Sets the suffix added to the extern wrapper functions generated for `static` and `static + /// inline` functions. #[arg(long, requires = "experimental", value_name = "SUFFIX")] wrap_non_extern_fns_suffix: Option, /// Enables experimental features. diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index e0cfe3817b..22ede0b9a0 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4564,15 +4564,11 @@ pub mod utils { .iter() .any(|h| file_is_cpp(h)); - let headers_path = - path.with_extension(if is_cpp { "hpp" } else { "h" }); let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" }); - let mut headers_file = File::create(&headers_path)?; let mut source_file = File::create(source_path)?; for item in &result.c_items { - writeln!(headers_file, "{}", item.header())?; writeln!(source_file, "{}", item.code())?; } diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index fa0e390cee..d530cd5e76 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -27,7 +27,6 @@ impl From for Error { #[derive(Debug)] pub(crate) struct CItem { - header: String, code: String, } @@ -41,7 +40,7 @@ impl CItem { let signature_type = ctx.resolve_type(function.signature()); match signature_type.kind() { TypeKind::Function(signature) => { - let mut buf = String::new(); + let mut code = String::new(); let mut count = 0; @@ -62,9 +61,13 @@ impl CItem { }) .collect::>(); - serialize_type(signature.return_type(), ctx, &mut buf)?; + serialize_type( + signature.return_type(), + ctx, + &mut code, + )?; write!( - buf, + code, " {}{}(", name, ctx.options() @@ -76,29 +79,25 @@ impl CItem { ", ", args.iter(), ctx, - &mut buf, + &mut code, |(name, type_id), ctx, buf| { serialize_type(*type_id, ctx, buf)?; write!(buf, " {}", name).map_err(Error::from) }, )?; - write!(buf, ")")?; - - let header = format!("{};", buf); - - write!(buf, " {{ return {}(", name)?; + write!(code, ") {{ return {}(", name)?; serialize_sep( ", ", args.iter(), ctx, - &mut buf, + &mut code, |(name, _), _, buf| { write!(buf, "{}", name).map_err(Error::from) }, )?; - write!(buf, "); }}")?; + write!(code, "); }}")?; - Ok(Self { header, code: buf }) + Ok(Self { code }) } _ => unreachable!(), } @@ -110,10 +109,6 @@ impl CItem { } } - pub(crate) fn header(&self) -> &str { - self.header.as_ref() - } - pub(crate) fn code(&self) -> &str { self.code.as_ref() } diff --git a/bindgen/lib.rs b/bindgen/lib.rs index b8e4d46a89..d58dd9ad42 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -1808,15 +1808,16 @@ impl Builder { } #[cfg(feature = "experimental")] - /// Whether to generate extern wrappers for inline functions. Defaults to false. + /// Whether to generate extern wrappers for `static` and `static inline` functions. Defaults to + /// false. pub fn wrap_non_extern_fns(mut self, doit: bool) -> Self { self.options.wrap_non_extern_fns = doit; self } #[cfg(feature = "experimental")] - /// Set the path of the header and source code files that would be created if any extern - /// wrapper functions must be generated due to the presence of non-extern functions. + /// Set the path for the source code file that would be created if any wrapper functions must + /// be generated due to the presence of non-extern functions. /// /// Bindgen will automatically add the right extension to the header and source code files. pub fn wrap_non_extern_fns_path>(mut self, path: T) -> Self { @@ -1825,7 +1826,8 @@ impl Builder { } #[cfg(feature = "experimental")] - /// Set the suffix added to the extern wrapper functions generated for inlined functions. + /// Set the suffix added to the extern wrapper functions generated for `static` and `static + /// inline` functions. pub fn wrap_non_extern_fns_suffix>( mut self, suffix: T, From d65527f52997784743ae411472ba7e097a6f0f83 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Jan 2023 13:44:49 -0500 Subject: [PATCH 11/37] keep code serialization in the happy path --- bindgen/codegen/serialize.rs | 131 ++++++++++++++++------------------- 1 file changed, 61 insertions(+), 70 deletions(-) diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index d530cd5e76..092e2644c2 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -35,78 +35,69 @@ impl CItem { function: &Function, ctx: &BindgenContext, ) -> Result { - match function.kind() { - FunctionKind::Function => { - let signature_type = ctx.resolve_type(function.signature()); - match signature_type.kind() { - TypeKind::Function(signature) => { - let mut code = String::new(); - - let mut count = 0; - - let name = function.name(); - let args = 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::>(); - - serialize_type( - signature.return_type(), - ctx, - &mut code, - )?; - write!( - code, - " {}{}(", - name, - ctx.options() - .wrap_non_extern_fns_suffix - .as_deref() - .unwrap_or(DEFAULT_NON_EXTERN_FNS_SUFFIX) - )?; - serialize_sep( - ", ", - args.iter(), - ctx, - &mut code, - |(name, type_id), ctx, buf| { - serialize_type(*type_id, ctx, buf)?; - write!(buf, " {}", name).map_err(Error::from) - }, - )?; - write!(code, ") {{ return {}(", name)?; - serialize_sep( - ", ", - args.iter(), - ctx, - &mut code, - |(name, _), _, buf| { - write!(buf, "{}", name).map_err(Error::from) - }, - )?; - write!(code, "); }}")?; - - Ok(Self { code }) - } - _ => unreachable!(), - } - } - function_kind => Err(Error::Serialize(format!( + if function.kind() != FunctionKind::Function { + return Err(Error::Serialize(format!( "Cannot serialize function kind {:?}", - function_kind - ))), + function.kind() + ))); } + let signature = match ctx.resolve_type(function.signature()).kind() { + TypeKind::Function(signature) => signature, + _ => unreachable!(), + }; + + let mut code = String::new(); + + let mut count = 0; + + let name = function.name(); + let args = 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::>(); + + serialize_type(signature.return_type(), ctx, &mut code)?; + write!( + code, + " {}{}(", + name, + ctx.options() + .wrap_non_extern_fns_suffix + .as_deref() + .unwrap_or(DEFAULT_NON_EXTERN_FNS_SUFFIX) + )?; + serialize_sep( + ", ", + args.iter(), + ctx, + &mut code, + |(name, type_id), ctx, buf| { + serialize_type(*type_id, ctx, buf)?; + write!(buf, " {}", name).map_err(Error::from) + }, + )?; + write!(code, ") {{ return {}(", name)?; + serialize_sep( + ", ", + args.iter(), + ctx, + &mut code, + |(name, _), _, buf| write!(buf, "{}", name).map_err(Error::from), + )?; + write!(code, "); }}")?; + + Ok(Self { code }) } pub(crate) fn code(&self) -> &str { From c80ed2d5dc71cdd34b01118f77b7598b5f324fe7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Jan 2023 15:14:55 -0500 Subject: [PATCH 12/37] rename `non-extern` to `static` --- bindgen-cli/options.rs | 24 +++++------ bindgen-integration/build.rs | 6 +-- .../expectations/tests/generated/README.md | 2 +- ...p-non-extern-fns.rs => wrap-static-fns.rs} | 0 ...rap-non-extern-fns.h => wrap-static-fns.h} | 2 +- bindgen-tests/tests/tests.rs | 6 +-- bindgen/codegen/mod.rs | 12 ++---- bindgen/codegen/serialize.rs | 2 +- bindgen/ir/context.rs | 4 +- bindgen/ir/function.rs | 16 ++----- bindgen/lib.rs | 42 +++++++++---------- 11 files changed, 49 insertions(+), 67 deletions(-) rename bindgen-tests/tests/expectations/tests/{wrap-non-extern-fns.rs => wrap-static-fns.rs} (100%) rename bindgen-tests/tests/headers/{wrap-non-extern-fns.h => wrap-static-fns.h} (67%) diff --git a/bindgen-cli/options.rs b/bindgen-cli/options.rs index 2d2645f576..458c7bab1f 100644 --- a/bindgen-cli/options.rs +++ b/bindgen-cli/options.rs @@ -355,15 +355,15 @@ struct BindgenCommand { with_derive_custom_union: Vec, /// Generate wrappers for `static` and `static inline` functions. #[arg(long, requires = "experimental")] - wrap_non_extern_fns: bool, + wrap_static_fns: bool, /// Sets the path for the source file that must be created due to the presence of `static` and /// `static inline` functions. #[arg(long, requires = "experimental", value_name = "PATH")] - wrap_non_extern_fns_path: Option, + wrap_static_fns_path: Option, /// Sets the suffix added to the extern wrapper functions generated for `static` and `static /// inline` functions. #[arg(long, requires = "experimental", value_name = "SUFFIX")] - wrap_non_extern_fns_suffix: Option, + wrap_static_fns_suffix: Option, /// Enables experimental features. #[arg(long)] experimental: bool, @@ -487,9 +487,9 @@ where with_derive_custom_struct, with_derive_custom_enum, with_derive_custom_union, - wrap_non_extern_fns, - wrap_non_extern_fns_path, - wrap_non_extern_fns_suffix, + wrap_static_fns, + wrap_static_fns_path, + wrap_static_fns_suffix, experimental: _, version, clang_args, @@ -996,16 +996,16 @@ where } } - if wrap_non_extern_fns { - builder = builder.wrap_non_extern_fns(true); + if wrap_static_fns { + builder = builder.wrap_static_fns(true); } - if let Some(path) = wrap_non_extern_fns_path { - builder = builder.wrap_non_extern_fns_path(path); + if let Some(path) = wrap_static_fns_path { + builder = builder.wrap_static_fns_path(path); } - if let Some(suffix) = wrap_non_extern_fns_suffix { - builder = builder.wrap_non_extern_fns_suffix(suffix); + if let Some(suffix) = wrap_static_fns_suffix { + builder = builder.wrap_static_fns_suffix(suffix); } Ok((builder, output, verbose)) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 0f1e454533..1ab7d2d80d 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -214,7 +214,7 @@ fn setup_extern_test() { let input_header_dir = PathBuf::from("../bindgen-tests/tests/headers/") .canonicalize() .expect("Cannot canonicalize libdir path"); - let input_header_file_path = input_header_dir.join("wrap-non-extern-fns.h"); + let input_header_file_path = input_header_dir.join("wrap-static-fns.h"); let input_header_file_path_str = input_header_file_path .to_str() .expect("Path could not be converted to a str"); @@ -223,8 +223,8 @@ fn setup_extern_test() { let bindings = Builder::default() .header(input_header_file_path_str) .parse_callbacks(Box::new(CargoCallbacks)) - .wrap_non_extern_fns(true) - .non_extern_fns_directory(out_path.display().to_string()) + .wrap_static_fns(true) + .static_fns_directory(out_path.display().to_string()) .generate() .expect("Unable to generate bindings"); diff --git a/bindgen-tests/tests/expectations/tests/generated/README.md b/bindgen-tests/tests/expectations/tests/generated/README.md index ce7e0f1b28..b4e8cabbf6 100644 --- a/bindgen-tests/tests/expectations/tests/generated/README.md +++ b/bindgen-tests/tests/expectations/tests/generated/README.md @@ -1,4 +1,4 @@ # Generated C, C++, Header files This directory contains files for features where extra files are generated -as a part of the feature. For example, `--wrap-non-extern-fns`. +as a part of the feature. For example, `--wrap-static-fns`. diff --git a/bindgen-tests/tests/expectations/tests/wrap-non-extern-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs similarity index 100% rename from bindgen-tests/tests/expectations/tests/wrap-non-extern-fns.rs rename to bindgen-tests/tests/expectations/tests/wrap-static-fns.rs diff --git a/bindgen-tests/tests/headers/wrap-non-extern-fns.h b/bindgen-tests/tests/headers/wrap-static-fns.h similarity index 67% rename from bindgen-tests/tests/headers/wrap-non-extern-fns.h rename to bindgen-tests/tests/headers/wrap-static-fns.h index 58a70a02f1..24e2c2c17b 100644 --- a/bindgen-tests/tests/headers/wrap-non-extern-fns.h +++ b/bindgen-tests/tests/headers/wrap-static-fns.h @@ -1,4 +1,4 @@ -// bindgen-flags: --experimental --wrap-non-extern-fns +// bindgen-flags: --experimental --wrap-static-fns static inline int foo() { return 11; diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 543a047700..94adbe48f9 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -728,9 +728,9 @@ fn test_extern_generated_headers() { println!("Out path is ::: {}", generated_path.display()); let _bindings = Builder::default() - .header("tests/headers/wrap-non-extern-fns.h") - .wrap_non_extern_fns(true) - .wrap_non_extern_fns_path(generated_path.display().to_string()) + .header("tests/headers/wrap-static-fns.h") + .wrap_static_fns(true) + .wrap_static_fns_path(generated_path.display().to_string()) .generate() .expect("Failed to generate bindings"); diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 22ede0b9a0..f37f95fe5e 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4008,7 +4008,7 @@ impl CodeGenerator for Function { let is_internal = matches!(self.linkage(), Linkage::Internal); if is_internal { - if ctx.options().wrap_non_extern_fns { + if ctx.options().wrap_static_fns { match CItem::from_function(self, ctx) { Ok(c_item) => result.c_items.push(c_item), Err(err) => warn!("Serialization failed: {:?}", err), @@ -4148,12 +4148,8 @@ impl CodeGenerator for Function { quote! { #[link(wasm_import_module = #name)] } }); - if is_internal && - ctx.options().wrap_non_extern_fns && - !has_link_name_attr - { - let name = - canonical_name.clone() + ctx.wrap_non_extern_fns_suffix(); + 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)); } @@ -4544,7 +4540,7 @@ pub mod utils { ) -> Result<(), std::io::Error> { let path = context .options() - .wrap_non_extern_fns_path + .wrap_static_fns_path .as_ref() .map(|path| PathBuf::from(path)) .unwrap_or_else(|| { diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 092e2644c2..9935b89459 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -73,7 +73,7 @@ impl CItem { " {}{}(", name, ctx.options() - .wrap_non_extern_fns_suffix + .wrap_static_fns_suffix .as_deref() .unwrap_or(DEFAULT_NON_EXTERN_FNS_SUFFIX) )?; diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index 06752699fd..6b5eb9af16 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -2793,9 +2793,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" } } - pub(crate) fn wrap_non_extern_fns_suffix(&self) -> &str { + pub(crate) fn wrap_static_fns_suffix(&self) -> &str { self.options() - .wrap_non_extern_fns_suffix + .wrap_static_fns_suffix .as_deref() .unwrap_or(crate::DEFAULT_NON_EXTERN_FNS_SUFFIX) } diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 3074fa97bf..62691ab845 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -94,9 +94,6 @@ pub struct Function { /// The linkage of the function. linkage: Linkage, - - /// Is this function inlined?. - is_inlined_function: bool, } impl Function { @@ -108,7 +105,6 @@ impl Function { comment: Option, kind: FunctionKind, linkage: Linkage, - is_inlined_function: bool, ) -> Self { Function { name, @@ -117,7 +113,6 @@ impl Function { comment, kind, linkage, - is_inlined_function, } } @@ -150,11 +145,6 @@ impl Function { pub fn linkage(&self) -> Linkage { self.linkage } - - /// Is this function inlined? - pub fn is_inlined_function(&self) -> bool { - self.is_inlined_function - } } impl DotAttributes for Function { @@ -696,7 +686,7 @@ impl ClangSubItemParser for Function { .map_or(false, |x| x.is_inlined_function()) { if !context.options().generate_inline_functions && - !context.options().wrap_non_extern_fns + !context.options().wrap_static_fns { return Err(ParseError::Continue); } @@ -705,7 +695,8 @@ impl ClangSubItemParser for Function { return Err(ParseError::Continue); } - if context.options().wrap_non_extern_fns && + // We cannot handle `inline` functions that are not `static`. + if context.options().wrap_static_fns && cursor.is_inlined_function() && matches!(linkage, Linkage::External) { @@ -752,7 +743,6 @@ impl ClangSubItemParser for Function { comment, kind, linkage, - cursor.is_inlined_function(), ); Ok(ParseResult::New(function, Some(cursor))) diff --git a/bindgen/lib.rs b/bindgen/lib.rs index d58dd9ad42..26c415de38 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -658,17 +658,17 @@ impl Builder { for callbacks in &self.options.parse_callbacks { output_vector.extend(callbacks.cli_args()); } - if self.options.wrap_non_extern_fns { - output_vector.push("--wrap-non-extern-fns".into()) + if self.options.wrap_static_fns { + output_vector.push("--wrap-static-fns".into()) } - if let Some(ref path) = self.options.wrap_non_extern_fns_path { - output_vector.push("--wrap-non-extern-fns-path".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_non_extern_fns_suffix { - output_vector.push("--wrap-non-extern-fns-suffix".into()); + if let Some(ref suffix) = self.options.wrap_static_fns_suffix { + output_vector.push("--wrap-static-fns-suffix".into()); output_vector.push(suffix.clone()); } @@ -1810,30 +1810,26 @@ impl Builder { #[cfg(feature = "experimental")] /// Whether to generate extern wrappers for `static` and `static inline` functions. Defaults to /// false. - pub fn wrap_non_extern_fns(mut self, doit: bool) -> Self { - self.options.wrap_non_extern_fns = doit; + 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 non-extern functions. + /// 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_non_extern_fns_path>(mut self, path: T) -> Self { - self.options.wrap_non_extern_fns_path = Some(path.as_ref().to_owned()); + pub fn wrap_static_fns_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_non_extern_fns_suffix>( - mut self, - suffix: T, - ) -> Self { - self.options.wrap_non_extern_fns_suffix = - Some(suffix.as_ref().to_owned()); + pub fn wrap_static_fns_suffix>(mut self, suffix: T) -> Self { + self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned()); self } } @@ -2177,11 +2173,11 @@ struct BindgenOptions { /// Whether to wrap unsafe operations in unsafe blocks or not. wrap_unsafe_ops: bool, - wrap_non_extern_fns: bool, + wrap_static_fns: bool, - wrap_non_extern_fns_suffix: Option, + wrap_static_fns_suffix: Option, - wrap_non_extern_fns_path: Option, + wrap_static_fns_path: Option, } impl BindgenOptions { @@ -2374,9 +2370,9 @@ impl Default for BindgenOptions { merge_extern_blocks, abi_overrides, wrap_unsafe_ops, - wrap_non_extern_fns, - wrap_non_extern_fns_suffix, - wrap_non_extern_fns_path, + wrap_static_fns, + wrap_static_fns_suffix, + wrap_static_fns_path, } } } From 9ecbde4e956b44204bc9174658afd0528c88b89d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 31 Jan 2023 12:58:19 -0500 Subject: [PATCH 13/37] Remove headers --- .../tests/expectations/tests/generated/extern.h | 2 -- bindgen-tests/tests/tests.rs | 14 -------------- 2 files changed, 16 deletions(-) delete mode 100644 bindgen-tests/tests/expectations/tests/generated/extern.h diff --git a/bindgen-tests/tests/expectations/tests/generated/extern.h b/bindgen-tests/tests/expectations/tests/generated/extern.h deleted file mode 100644 index cd99194f26..0000000000 --- a/bindgen-tests/tests/expectations/tests/generated/extern.h +++ /dev/null @@ -1,2 +0,0 @@ -int foo__extern(); -int bar__extern(); diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 94adbe48f9..85183acd97 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -736,13 +736,9 @@ fn test_extern_generated_headers() { let expected_c = fs::read_to_string(expect_path.with_extension("c")) .expect("Could not read generated extern.c"); - let expected_h = fs::read_to_string(expect_path.with_extension("h")) - .expect("Could not read generated extern.h"); let actual_c = fs::read_to_string(generated_path.with_extension("c")) .expect("Could not read actual extern.c"); - let actual_h = fs::read_to_string(generated_path.with_extension("h")) - .expect("Could not read actual extern.h"); if expected_c != actual_c { error_diff_mismatch( @@ -753,14 +749,4 @@ fn test_extern_generated_headers() { ) .unwrap(); } - - if expected_h != actual_h { - error_diff_mismatch( - &actual_h, - &expected_h, - None, - &expect_path.with_extension("h"), - ) - .unwrap(); - } } From 34278f4af48e276d28dc42e9b56b4d943e8a52bf Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 31 Jan 2023 13:05:11 -0500 Subject: [PATCH 14/37] update integration tests --- bindgen-integration/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 1ab7d2d80d..97a877035e 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -224,7 +224,7 @@ fn setup_extern_test() { .header(input_header_file_path_str) .parse_callbacks(Box::new(CargoCallbacks)) .wrap_static_fns(true) - .static_fns_directory(out_path.display().to_string()) + .wrap_static_fns_path(out_path.join("extern").display().to_string()) .generate() .expect("Unable to generate bindings"); From eb2a3d369e8b59db0d1bc5af6b3a3addb778e6be Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 31 Jan 2023 13:10:58 -0500 Subject: [PATCH 15/37] run rustfmt --- bindgen/ir/function.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs index 62691ab845..baa2c36ca4 100644 --- a/bindgen/ir/function.rs +++ b/bindgen/ir/function.rs @@ -736,14 +736,8 @@ impl ClangSubItemParser for Function { let mangled_name = cursor_mangling(context, &cursor); let comment = cursor.raw_comment(); - let function = Self::new( - name.clone(), - mangled_name, - sig, - comment, - kind, - linkage, - ); + let function = + Self::new(name.clone(), mangled_name, sig, comment, kind, linkage); Ok(ParseResult::New(function, Some(cursor))) } From 595ce787155a85fe9bf74615cf277916ec270f39 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 31 Jan 2023 13:21:00 -0500 Subject: [PATCH 16/37] add experimental feature to dependency --- bindgen-integration/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindgen-integration/Cargo.toml b/bindgen-integration/Cargo.toml index e2abb6e2ed..60f0426a76 100644 --- a/bindgen-integration/Cargo.toml +++ b/bindgen-integration/Cargo.toml @@ -7,7 +7,7 @@ publish = false build = "build.rs" [build-dependencies] -bindgen = { path = "../bindgen" } +bindgen = { path = "../bindgen", features = ["experimental"] } cc = "1.0" [features] From cb93924d7ecee4f463807348a26054c482f5893b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 31 Jan 2023 13:45:14 -0500 Subject: [PATCH 17/37] use static kind --- bindgen-integration/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 97a877035e..d0dd004f8e 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -228,7 +228,7 @@ fn setup_extern_test() { .generate() .expect("Unable to generate bindings"); - println!("cargo:rustc-link-lib=extern"); // tell cargo to link libextern + println!("cargo:rustc-link-lib=static=extern"); // tell cargo to link libextern println!("bindings generated: {}", bindings); let obj_path = out_path.join("extern.o"); From e36e088e63e79a97fcac572da87c63bcb88754a4 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 31 Jan 2023 14:47:34 -0500 Subject: [PATCH 18/37] force function names --- .../expectations/tests/generated/extern.c | 6 +++-- bindgen/codegen/serialize.rs | 22 ++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/generated/extern.c b/bindgen-tests/tests/expectations/tests/generated/extern.c index f6e1ad01ec..d4e530b365 100644 --- a/bindgen-tests/tests/expectations/tests/generated/extern.c +++ b/bindgen-tests/tests/expectations/tests/generated/extern.c @@ -1,2 +1,4 @@ -int foo__extern() { return foo(); } -int bar__extern() { return bar(); } +int foo__extern() asm("foo__extern"); +foo__extern() { return foo(); } +int bar__extern() asm("bar__extern"); +bar__extern() { return bar(); } diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 9935b89459..b25e5c803c 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -67,16 +67,17 @@ impl CItem { }) .collect::>(); - serialize_type(signature.return_type(), ctx, &mut code)?; - write!( - code, - " {}{}(", + let wrap_name = format!( + "{}{}", name, ctx.options() .wrap_static_fns_suffix .as_deref() .unwrap_or(DEFAULT_NON_EXTERN_FNS_SUFFIX) - )?; + ); + + serialize_type(signature.return_type(), ctx, &mut code)?; + write!(code, " {}(", wrap_name)?; serialize_sep( ", ", args.iter(), @@ -87,6 +88,17 @@ impl CItem { write!(buf, " {}", name).map_err(Error::from) }, )?; + writeln!(code, ") asm(\"{}\");", wrap_name)?; + + write!(code, "{}(", wrap_name)?; + serialize_sep( + ", ", + args.iter(), + ctx, + &mut code, + |(name, _), _, buf| write!(buf, "{}", name).map_err(Error::from), + )?; + write!(code, ") {{ return {}(", name)?; serialize_sep( ", ", From ceebca1e9c2829057948dcf41213050ba2515077 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 31 Jan 2023 15:39:11 -0500 Subject: [PATCH 19/37] refactor c serialization --- bindgen/codegen/mod.rs | 27 ++- bindgen/codegen/serialize.rs | 370 ++++++++++++++++++----------------- 2 files changed, 198 insertions(+), 199 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index f37f95fe5e..f3d3598857 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -47,7 +47,6 @@ use crate::ir::template::{ }; use crate::ir::ty::{Type, TypeKind}; use crate::ir::var::Var; -use serialize::CItem; use proc_macro2::{self, Ident, Span}; use quote::TokenStreamExt; @@ -244,7 +243,7 @@ struct CodegenResult<'a> { /// that name. This lets us give each overload a unique suffix. overload_counters: HashMap, - c_items: Vec, + items_to_serialize: Vec, } impl<'a> CodegenResult<'a> { @@ -262,7 +261,7 @@ impl<'a> CodegenResult<'a> { functions_seen: Default::default(), vars_seen: Default::default(), overload_counters: Default::default(), - c_items: Default::default(), + items_to_serialize: Default::default(), } } @@ -307,7 +306,7 @@ impl<'a> CodegenResult<'a> { } /// Get the overload number for the given function name. Increments the - /// counter internally so the next time we ask for the overload for this + /// counter internally so the next time we ask for the loverload for this /// name, we get the incremented value, and so on. fn overload_number(&mut self, name: &str) -> u32 { let counter = self.overload_counters.entry(name.into()).or_insert(0); @@ -4009,10 +4008,7 @@ impl CodeGenerator for Function { if is_internal { if ctx.options().wrap_static_fns { - match CItem::from_function(self, ctx) { - Ok(c_item) => result.c_items.push(c_item), - Err(err) => warn!("Serialization failed: {:?}", err), - } + 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. @@ -4508,8 +4504,8 @@ pub(crate) fn codegen( result.push(dynamic_items_tokens); } - if !result.c_items.is_empty() { - match utils::serialize_c_items(&result, &context) { + if !result.items_to_serialize.is_empty() { + match utils::serialize_items(&result, &context) { Ok(()) => (), Err(err) => warn!("Could not serialize C items: {}", err), } @@ -4520,6 +4516,7 @@ pub(crate) fn codegen( } pub mod utils { + use super::serialize::CSerialize; use super::{error, CodegenResult, ToRustTyOrOpaque}; use crate::ir::context::BindgenContext; use crate::ir::function::{Abi, ClangAbi, FunctionSig}; @@ -4529,15 +4526,14 @@ pub mod utils { use proc_macro2; use std::borrow::Cow; use std::fs::File; - use std::io::Write; use std::mem; use std::path::PathBuf; use std::str::FromStr; - pub(super) fn serialize_c_items( + pub(super) fn serialize_items( result: &CodegenResult, context: &BindgenContext, - ) -> Result<(), std::io::Error> { + ) -> std::io::Result<()> { let path = context .options() .wrap_static_fns_path @@ -4564,8 +4560,9 @@ pub mod utils { let mut source_file = File::create(source_path)?; - for item in &result.c_items { - writeln!(source_file, "{}", item.code())?; + for &id in &result.items_to_serialize { + let item = context.resolve_item(id); + item.serialize(context, &mut source_file)?; } Ok(()) diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index b25e5c803c..1017240002 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -1,125 +1,219 @@ -use std::fmt::{self, Write}; +use std::io::{self, Write}; use crate::callbacks::IntKind; -use crate::DEFAULT_NON_EXTERN_FNS_SUFFIX; use crate::ir::context::{BindgenContext, TypeId}; use crate::ir::function::{Function, FunctionKind}; -use crate::ir::ty::{FloatKind, TypeKind}; +use crate::ir::item::Item; +use crate::ir::item_kind::ItemKind; +use crate::ir::ty::{FloatKind, Type, TypeKind}; -#[derive(Debug)] -pub(crate) enum Error { - Serialize(String), - Fmt(fmt::Error), -} - -impl From for Error { - fn from(err: fmt::Error) -> Self { - Self::Fmt(err) - } +pub(crate) trait CSerialize { + fn serialize( + &self, + ctx: &BindgenContext, + writer: &mut W, + ) -> io::Result<()>; } -impl From for Error { - fn from(err: String) -> Self { - Self::Serialize(err) +impl CSerialize for Item { + fn serialize( + &self, + ctx: &BindgenContext, + writer: &mut W, + ) -> io::Result<()> { + match self.kind() { + ItemKind::Function(func) => func.serialize(ctx, writer), + kind => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Cannot serialize item kind {:?}", kind), + )); + } + } } } -#[derive(Debug)] -pub(crate) struct CItem { - code: String, -} - -impl CItem { - pub(crate) fn from_function( - function: &Function, +impl CSerialize for Function { + fn serialize( + &self, ctx: &BindgenContext, - ) -> Result { - if function.kind() != FunctionKind::Function { - return Err(Error::Serialize(format!( - "Cannot serialize function kind {:?}", - function.kind() - ))); + writer: &mut W, + ) -> io::Result<()> { + if self.kind() != FunctionKind::Function { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Cannot serialize function kind {:?}", self.kind()), + )); } - let signature = match ctx.resolve_type(function.signature()).kind() { + + let signature = match ctx.resolve_type(self.signature()).kind() { TypeKind::Function(signature) => signature, _ => unreachable!(), }; - let mut code = String::new(); - - let mut count = 0; - - let name = function.name(); - let args = 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::>(); - - let wrap_name = format!( - "{}{}", - name, - ctx.options() - .wrap_static_fns_suffix - .as_deref() - .unwrap_or(DEFAULT_NON_EXTERN_FNS_SUFFIX) - ); - - serialize_type(signature.return_type(), ctx, &mut code)?; - write!(code, " {}(", wrap_name)?; - serialize_sep( - ", ", - args.iter(), - ctx, - &mut code, - |(name, type_id), ctx, buf| { - serialize_type(*type_id, ctx, buf)?; - write!(buf, " {}", name).map_err(Error::from) - }, - )?; - writeln!(code, ") asm(\"{}\");", wrap_name)?; + 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::>() + }; - write!(code, "{}(", wrap_name)?; - serialize_sep( - ", ", - args.iter(), - ctx, - &mut code, - |(name, _), _, buf| write!(buf, "{}", name).map_err(Error::from), - )?; + // The name used for the wrapper self. + let wrap_name = format!("{}{}", name, ctx.wrap_static_fns_suffix()); - write!(code, ") {{ return {}(", name)?; + // Write `ret_ty wrap_name(args) asm("wrap_name");` + signature.return_type().serialize(ctx, writer)?; + write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", args.iter(), ctx, - &mut code, - |(name, _), _, buf| write!(buf, "{}", name).map_err(Error::from), + writer, + |(name, type_id), ctx, buf| { + type_id.serialize(ctx, buf)?; + write!(buf, " {}", name) + }, )?; - write!(code, "); }}")?; + writeln!(writer, ") asm(\"{}\");", wrap_name)?; + + // Write `wrap_name(arg_names) { return name(arg_names)' }` + write!(writer, "{}(", wrap_name)?; + serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| { + write!(buf, "{}", name) + })?; + write!(writer, ") {{ return {}(", name)?; + serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| { + write!(buf, "{}", name) + })?; + writeln!(writer, "); }}")?; + + Ok(()) + } +} - Ok(Self { code }) +impl CSerialize for TypeId { + fn serialize( + &self, + ctx: &BindgenContext, + writer: &mut W, + ) -> io::Result<()> { + ctx.resolve_type(*self).serialize(ctx, writer) } +} + +impl CSerialize for Type { + fn serialize( + &self, + ctx: &BindgenContext, + writer: &mut W, + ) -> io::Result<()> { + match self.kind() { + TypeKind::Void => write!(writer, "void")?, + TypeKind::NullPtr => write!(writer, "nullptr_t")?, + TypeKind::Int(int_kind) => 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")?, + int_kind => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Cannot serialize integer kind {:?}", int_kind), + )) + } + }, + TypeKind::Float(float_kind) => 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) => 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) => { type_id.serialize(ctx, writer) }?, + TypeKind::TemplateAlias(type_id, params) => { + type_id.serialize(ctx, writer)?; + write!(writer, "<")?; + serialize_sep( + ", ", + params.iter(), + ctx, + writer, + TypeId::serialize, + )?; + write!(writer, ">")? + } + TypeKind::Array(type_id, length) => { + type_id.serialize(ctx, writer)?; + write!(writer, " [{}]", length)? + } + TypeKind::Function(signature) => { + signature.return_type().serialize(ctx, writer)?; + write!(writer, " (")?; + serialize_sep( + ", ", + signature.argument_types().iter(), + ctx, + writer, + |(name, type_id), ctx, buf| { + type_id.serialize(ctx, buf)?; + + if let Some(name) = name { + write!(buf, "{}", name)?; + } + + Ok(()) + }, + )?; + write!(writer, ")")? + } + TypeKind::ResolvedTypeRef(type_id) => { + type_id.serialize(ctx, writer)? + } + ty => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("Cannot serialize type kind {:?}", ty), + )) + } + }; - pub(crate) fn code(&self) -> &str { - self.code.as_ref() + Ok(()) } } fn serialize_sep< - W: fmt::Write, - F: Fn(I::Item, &BindgenContext, &mut W) -> Result<(), Error>, + W: io::Write, + F: Fn(I::Item, &BindgenContext, &mut W) -> io::Result<()>, I: Iterator, >( sep: &'static str, @@ -127,10 +221,9 @@ fn serialize_sep< ctx: &BindgenContext, buf: &mut W, f: F, -) -> Result<(), Error> { +) -> io::Result<()> { if let Some(item) = iter.next() { f(item, ctx, buf)?; - for item in iter { write!(buf, "{}", sep)?; f(item, ctx, buf)?; @@ -139,94 +232,3 @@ fn serialize_sep< Ok(()) } - -fn serialize_type( - type_id: TypeId, - ctx: &BindgenContext, - buf: &mut W, -) -> Result<(), Error> { - match ctx.resolve_type(type_id).kind() { - TypeKind::Void => write!(buf, "void")?, - TypeKind::NullPtr => write!(buf, "nullptr_t")?, - TypeKind::Int(int_kind) => match int_kind { - IntKind::Bool => write!(buf, "bool")?, - IntKind::SChar => write!(buf, "signed char")?, - IntKind::UChar => write!(buf, "unsigned char")?, - IntKind::WChar => write!(buf, "wchar_t")?, - IntKind::Short => write!(buf, "short")?, - IntKind::UShort => write!(buf, "unsigned short")?, - IntKind::Int => write!(buf, "int")?, - IntKind::UInt => write!(buf, "unsigned int")?, - IntKind::Long => write!(buf, "long")?, - IntKind::ULong => write!(buf, "unsigned long")?, - IntKind::LongLong => write!(buf, "long long")?, - IntKind::ULongLong => write!(buf, "unsigned long long")?, - int_kind => { - return Err(Error::Serialize(format!( - "Cannot serialize integer kind {:?}", - int_kind - ))) - } - }, - TypeKind::Float(float_kind) => match float_kind { - FloatKind::Float => write!(buf, "float")?, - FloatKind::Double => write!(buf, "double")?, - FloatKind::LongDouble => write!(buf, "long double")?, - FloatKind::Float128 => write!(buf, "__float128")?, - }, - TypeKind::Complex(float_kind) => match float_kind { - FloatKind::Float => write!(buf, "float complex")?, - FloatKind::Double => write!(buf, "double complex")?, - FloatKind::LongDouble => write!(buf, "long double complex")?, - FloatKind::Float128 => write!(buf, "__complex128")?, - }, - TypeKind::Alias(type_id) => serialize_type(*type_id, ctx, buf)?, - TypeKind::TemplateAlias(type_id, params) => { - serialize_type(*type_id, ctx, buf)?; - write!(buf, "<")?; - serialize_sep( - ", ", - params.iter().copied(), - ctx, - buf, - serialize_type, - )?; - write!(buf, ">")? - } - TypeKind::Array(type_id, length) => { - serialize_type(*type_id, ctx, buf)?; - write!(buf, " [{}]", length)? - } - TypeKind::Function(signature) => { - serialize_type(signature.return_type(), ctx, buf)?; - write!(buf, " (")?; - serialize_sep( - ", ", - signature.argument_types().iter(), - ctx, - buf, - |(name, type_id), ctx, buf| { - serialize_type(*type_id, ctx, buf)?; - - if let Some(name) = name { - write!(buf, "{}", name)?; - } - - Ok(()) - }, - )?; - write!(buf, ")")? - } - TypeKind::ResolvedTypeRef(type_id) => { - serialize_type(*type_id, ctx, buf)? - } - ty => { - return Err(Error::Serialize(format!( - "Cannot serialize type kind {:?}", - ty - ))) - } - }; - - Ok(()) -} From f7df058f6110df610df399cec2afba1cdcba5e80 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 1 Feb 2023 11:23:27 -0500 Subject: [PATCH 20/37] add types for serialized functions and support pointer types --- bindgen-integration/build.rs | 31 ++++++++++--------- bindgen-integration/src/lib.rs | 5 ++- .../expectations/tests/generated/extern.c | 6 ++-- .../expectations/tests/wrap-static-fns.rs | 4 +++ bindgen-tests/tests/headers/wrap-static-fns.h | 4 +++ bindgen/codegen/serialize.rs | 26 ++++++++++++---- 6 files changed, 53 insertions(+), 23 deletions(-) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index d0dd004f8e..00deb6f132 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -205,7 +205,7 @@ fn setup_macro_test() { ); } -fn setup_extern_test() { +fn setup_wrap_static_fns_test() { // GH-1090: https://github.com/rust-lang/rust-bindgen/issues/1090 // set output directory under /target so it is easy to clean generated files let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); @@ -235,7 +235,7 @@ fn setup_extern_test() { let lib_path = out_path.join("libextern.a"); // build the external files to check if they work - if !std::process::Command::new("clang") + let clang_output = std::process::Command::new("clang") .arg("-c") .arg("-o") .arg(&obj_path) @@ -243,23 +243,26 @@ fn setup_extern_test() { .arg("-include") .arg(input_header_file_path) .output() - .expect("`clang` command error") - .status - .success() - { - panic!("Could not compile object file"); + .expect("`clang` command error"); + if !clang_output.status.success() { + panic!( + "Could not compile object file:\n{}", + String::from_utf8_lossy(&clang_output.stderr) + ); } - if !std::process::Command::new("ar") + let ar_output = std::process::Command::new("ar") .arg("rcs") .arg(lib_path) .arg(obj_path) .output() - .expect("`ar` command error") - .status - .success() - { - panic!("Could not emit library file"); + .expect("`ar` command error"); + + if !ar_output.status.success() { + panic!( + "Could not emit library file:\n{}", + String::from_utf8_lossy(&ar_output.stderr) + ); } bindings @@ -269,5 +272,5 @@ fn setup_extern_test() { fn main() { setup_macro_test(); - setup_extern_test(); + setup_wrap_static_fns_test(); } diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index f5ef8644b9..5c6f0c6018 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -292,7 +292,7 @@ fn test_custom_derive() { } #[test] -fn test_extern_bindings() { +fn test_wrap_static_fns() { // GH-1090: https://github.com/rust-lang/rust-bindgen/issues/1090 unsafe { let f = extern_bindings::foo(); @@ -300,5 +300,8 @@ fn test_extern_bindings() { let b = extern_bindings::bar(); assert_eq!(1, b); + + let t = extern_bindings::takes_ptr(&mut 1); + assert_eq!(2, t); } } diff --git a/bindgen-tests/tests/expectations/tests/generated/extern.c b/bindgen-tests/tests/expectations/tests/generated/extern.c index d4e530b365..5fbf1bdb7a 100644 --- a/bindgen-tests/tests/expectations/tests/generated/extern.c +++ b/bindgen-tests/tests/expectations/tests/generated/extern.c @@ -1,4 +1,6 @@ int foo__extern() asm("foo__extern"); -foo__extern() { return foo(); } +int foo__extern() { return foo(); } int bar__extern() asm("bar__extern"); -bar__extern() { return bar(); } +int bar__extern() { return bar(); } +int takes_ptr__extern(int* arg) asm("takes_ptr__extern"); +int takes_ptr__extern(int*arg) { return takes_ptr(arg); } diff --git a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs index c4b81f1a0b..01fef831c0 100644 --- a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs +++ b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs @@ -13,3 +13,7 @@ extern "C" { #[link_name = "\u{1}bar__extern"] pub fn bar() -> ::std::os::raw::c_int; } +extern "C" { + #[link_name = "\u{1}takes_ptr__extern"] + pub fn takes_ptr(arg: *mut ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/headers/wrap-static-fns.h b/bindgen-tests/tests/headers/wrap-static-fns.h index 24e2c2c17b..0f4b36f9f3 100644 --- a/bindgen-tests/tests/headers/wrap-static-fns.h +++ b/bindgen-tests/tests/headers/wrap-static-fns.h @@ -9,3 +9,7 @@ static int bar() { inline int baz() { return 2; } + +static inline int takes_ptr(int* arg) { + return *arg + 1; +} diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 1017240002..8676c0f9e1 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -77,9 +77,11 @@ impl CSerialize for Function { // 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");` - signature.return_type().serialize(ctx, writer)?; + ret_ty.serialize(ctx, writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -93,11 +95,19 @@ impl CSerialize for Function { )?; writeln!(writer, ") asm(\"{}\");", wrap_name)?; - // Write `wrap_name(arg_names) { return name(arg_names)' }` - write!(writer, "{}(", wrap_name)?; - serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| { - write!(buf, "{}", name) - })?; + // Write `ret_ty wrap_name(args) { return name(arg_names)' }` + ret_ty.serialize(ctx, writer)?; + write!(writer, " {}(", wrap_name)?; + serialize_sep( + ", ", + args.iter(), + ctx, + writer, + |(name, type_id), _, buf| { + type_id.serialize(ctx, buf)?; + write!(buf, "{}", name) + }, + )?; write!(writer, ") {{ return {}(", name)?; serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| { write!(buf, "{}", name) @@ -199,6 +209,10 @@ impl CSerialize for Type { TypeKind::ResolvedTypeRef(type_id) => { type_id.serialize(ctx, writer)? } + TypeKind::Pointer(type_id) => { + type_id.serialize(ctx, writer)?; + write!(writer, "*")?; + } ty => { return Err(io::Error::new( io::ErrorKind::Other, From c55aa5be396bbbff5a18b6d4ce09270dff10e8eb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 1 Feb 2023 12:52:08 -0500 Subject: [PATCH 21/37] buffer all the code before writing --- bindgen/codegen/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index f3d3598857..65e581cafb 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4525,7 +4525,6 @@ pub mod utils { use crate::{args_are_cpp, file_is_cpp}; use proc_macro2; use std::borrow::Cow; - use std::fs::File; use std::mem; use std::path::PathBuf; use std::str::FromStr; @@ -4558,13 +4557,15 @@ pub mod utils { let source_path = path.with_extension(if is_cpp { "cpp" } else { "c" }); - let mut source_file = File::create(source_path)?; + let mut code = Vec::new(); for &id in &result.items_to_serialize { let item = context.resolve_item(id); - item.serialize(context, &mut source_file)?; + item.serialize(context, &mut code)?; } + std::fs::write(source_path, code)?; + Ok(()) } From c12645f952a7673b5ba957b0318cd2df6a828700 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 12:27:04 -0500 Subject: [PATCH 22/37] stop bindgen if there's a serialization error --- bindgen/codegen/mod.rs | 40 +++++++++++++++++++------ bindgen/codegen/serialize.rs | 58 +++++++++++++++++++----------------- bindgen/ir/context.rs | 9 +++--- bindgen/lib.rs | 9 +++++- 4 files changed, 74 insertions(+), 42 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 65e581cafb..b531e15e98 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -60,6 +60,27 @@ use std::iter; use std::ops; use std::str::FromStr; +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum CodegenError { + Serialize(String), + Io(String), +} + +impl From 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(err) => err.fmt(f), + CodegenError::Io(err) => err.fmt(f), + } + } +} + // Name of type defined in constified enum module pub static CONSTIFIED_ENUM_MODULE_REPR_NAME: &str = "Type"; @@ -4454,7 +4475,8 @@ impl CodeGenerator for ObjCInterface { pub(crate) fn codegen( context: BindgenContext, -) -> (proc_macro2::TokenStream, BindgenOptions, Vec) { +) -> Result<(proc_macro2::TokenStream, BindgenOptions, Vec), CodegenError> +{ context.gen(|context| { let _t = context.timer("codegen"); let counter = Cell::new(0); @@ -4505,19 +4527,19 @@ pub(crate) fn codegen( } if !result.items_to_serialize.is_empty() { - match utils::serialize_items(&result, &context) { - Ok(()) => (), - Err(err) => warn!("Could not serialize C items: {}", err), - } + utils::serialize_items(&result, context)?; } - postprocessing::postprocessing(result.items, context.options()) + Ok(postprocessing::postprocessing( + result.items, + context.options(), + )) }) } pub mod utils { use super::serialize::CSerialize; - use super::{error, CodegenResult, ToRustTyOrOpaque}; + use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; use crate::ir::context::BindgenContext; use crate::ir::function::{Abi, ClangAbi, FunctionSig}; use crate::ir::item::{Item, ItemCanonicalPath}; @@ -4532,12 +4554,12 @@ pub mod utils { pub(super) fn serialize_items( result: &CodegenResult, context: &BindgenContext, - ) -> std::io::Result<()> { + ) -> Result<(), CodegenError> { let path = context .options() .wrap_static_fns_path .as_ref() - .map(|path| PathBuf::from(path)) + .map(PathBuf::from) .unwrap_or_else(|| { std::env::temp_dir().join("bindgen").join("extern") }); diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 8676c0f9e1..32cf50fc9c 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -1,4 +1,4 @@ -use std::io::{self, Write}; +use std::io::Write; use crate::callbacks::IntKind; @@ -8,12 +8,14 @@ use crate::ir::item::Item; use crate::ir::item_kind::ItemKind; use crate::ir::ty::{FloatKind, Type, TypeKind}; +use super::CodegenError; + pub(crate) trait CSerialize { fn serialize( &self, ctx: &BindgenContext, writer: &mut W, - ) -> io::Result<()>; + ) -> Result<(), CodegenError>; } impl CSerialize for Item { @@ -21,14 +23,14 @@ impl CSerialize for Item { &self, ctx: &BindgenContext, writer: &mut W, - ) -> io::Result<()> { + ) -> Result<(), CodegenError> { match self.kind() { ItemKind::Function(func) => func.serialize(ctx, writer), kind => { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Cannot serialize item kind {:?}", kind), - )); + return Err(CodegenError::Serialize(format!( + "Cannot serialize item kind {:?}", + kind + ))); } } } @@ -39,12 +41,12 @@ impl CSerialize for Function { &self, ctx: &BindgenContext, writer: &mut W, - ) -> io::Result<()> { + ) -> Result<(), CodegenError> { if self.kind() != FunctionKind::Function { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Cannot serialize function kind {:?}", self.kind()), - )); + return Err(CodegenError::Serialize(format!( + "Cannot serialize function kind {:?}", + self.kind() + ))); } let signature = match ctx.resolve_type(self.signature()).kind() { @@ -90,7 +92,7 @@ impl CSerialize for Function { writer, |(name, type_id), ctx, buf| { type_id.serialize(ctx, buf)?; - write!(buf, " {}", name) + write!(buf, " {}", name).map_err(From::from) }, )?; writeln!(writer, ") asm(\"{}\");", wrap_name)?; @@ -105,12 +107,12 @@ impl CSerialize for Function { writer, |(name, type_id), _, buf| { type_id.serialize(ctx, buf)?; - write!(buf, "{}", name) + write!(buf, "{}", name).map_err(From::from) }, )?; write!(writer, ") {{ return {}(", name)?; serialize_sep(", ", args.iter(), ctx, writer, |(name, _), _, buf| { - write!(buf, "{}", name) + write!(buf, "{}", name).map_err(From::from) })?; writeln!(writer, "); }}")?; @@ -123,7 +125,7 @@ impl CSerialize for TypeId { &self, ctx: &BindgenContext, writer: &mut W, - ) -> io::Result<()> { + ) -> Result<(), CodegenError> { ctx.resolve_type(*self).serialize(ctx, writer) } } @@ -133,7 +135,7 @@ impl CSerialize for Type { &self, ctx: &BindgenContext, writer: &mut W, - ) -> io::Result<()> { + ) -> Result<(), CodegenError> { match self.kind() { TypeKind::Void => write!(writer, "void")?, TypeKind::NullPtr => write!(writer, "nullptr_t")?, @@ -151,10 +153,10 @@ impl CSerialize for Type { IntKind::LongLong => write!(writer, "long long")?, IntKind::ULongLong => write!(writer, "unsigned long long")?, int_kind => { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Cannot serialize integer kind {:?}", int_kind), - )) + return Err(CodegenError::Serialize(format!( + "Cannot serialize integer kind {:?}", + int_kind + ))) } }, TypeKind::Float(float_kind) => match float_kind { @@ -214,10 +216,10 @@ impl CSerialize for Type { write!(writer, "*")?; } ty => { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("Cannot serialize type kind {:?}", ty), - )) + return Err(CodegenError::Serialize(format!( + "Cannot serialize type kind {:?}", + ty + ))) } }; @@ -226,8 +228,8 @@ impl CSerialize for Type { } fn serialize_sep< - W: io::Write, - F: Fn(I::Item, &BindgenContext, &mut W) -> io::Result<()>, + W: Write, + F: Fn(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>, I: Iterator, >( sep: &'static str, @@ -235,7 +237,7 @@ fn serialize_sep< ctx: &BindgenContext, buf: &mut W, f: F, -) -> io::Result<()> { +) -> Result<(), CodegenError> { if let Some(item) = iter.next() { f(item, ctx, buf)?; for item in iter { diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index 6b5eb9af16..b693a7047e 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( mut self, cb: F, - ) -> (Out, BindgenOptions, Vec) + ) -> Result<(Out, BindgenOptions, Vec), CodegenError> where - F: FnOnce(&Self) -> Out, + F: FnOnce(&Self) -> Result, { 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 diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 26c415de38..5f995c4e8c 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::{ @@ -2415,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 { @@ -2432,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) + } } } } @@ -2658,7 +2664,8 @@ impl Bindings { parse(&mut context)?; } - let (module, options, warnings) = codegen::codegen(context); + let (module, options, warnings) = + codegen::codegen(context).map_err(BindgenError::Codegen)?; Ok(Bindings { options, From 3eb7f69a27cb436073fbec13f3dd4ebf56453c60 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 12:34:05 -0500 Subject: [PATCH 23/37] add missing space --- bindgen/codegen/serialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 32cf50fc9c..3b2c8ed5ec 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -107,7 +107,7 @@ impl CSerialize for Function { writer, |(name, type_id), _, buf| { type_id.serialize(ctx, buf)?; - write!(buf, "{}", name).map_err(From::from) + write!(buf, " {}", name).map_err(From::from) }, )?; write!(writer, ") {{ return {}(", name)?; From b682c6ce78035c0471cd9b8ce7de22e076552bdd Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 13:05:21 -0500 Subject: [PATCH 24/37] track location while reporting errors --- bindgen/codegen/mod.rs | 8 ++-- bindgen/codegen/serialize.rs | 93 ++++++++++++++++++++++++------------ 2 files changed, 68 insertions(+), 33 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index b531e15e98..4ff853248b 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -62,7 +62,7 @@ use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CodegenError { - Serialize(String), + Serialize { msg: String, loc: String }, Io(String), } @@ -75,7 +75,9 @@ impl From for CodegenError { impl std::fmt::Display for CodegenError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - CodegenError::Serialize(err) => err.fmt(f), + CodegenError::Serialize { msg, loc } => { + write!(f, "serialization error at {}: {}", loc, msg) + } CodegenError::Io(err) => err.fmt(f), } } @@ -4583,7 +4585,7 @@ pub mod utils { for &id in &result.items_to_serialize { let item = context.resolve_item(id); - item.serialize(context, &mut code)?; + item.serialize(context, item, &mut code)?; } std::fs::write(source_path, code)?; diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 3b2c8ed5ec..9ec8e4a357 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -10,10 +10,17 @@ 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 { fn serialize( &self, ctx: &BindgenContext, + item: &Item, writer: &mut W, ) -> Result<(), CodegenError>; } @@ -22,15 +29,16 @@ impl CSerialize for Item { fn serialize( &self, ctx: &BindgenContext, + item: &Item, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { - ItemKind::Function(func) => func.serialize(ctx, writer), + ItemKind::Function(func) => func.serialize(ctx, item, writer), kind => { - return Err(CodegenError::Serialize(format!( - "Cannot serialize item kind {:?}", - kind - ))); + return Err(CodegenError::Serialize { + msg: format!("Cannot serialize item kind {:?}", kind), + loc: get_loc(item), + }); } } } @@ -40,13 +48,17 @@ impl CSerialize for Function { fn serialize( &self, ctx: &BindgenContext, + item: &Item, writer: &mut W, ) -> Result<(), CodegenError> { if self.kind() != FunctionKind::Function { - return Err(CodegenError::Serialize(format!( - "Cannot serialize function kind {:?}", - self.kind() - ))); + 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() { @@ -83,7 +95,7 @@ impl CSerialize for Function { let ret_ty = signature.return_type(); // Write `ret_ty wrap_name(args) asm("wrap_name");` - ret_ty.serialize(ctx, writer)?; + ret_ty.serialize(ctx, ctx.resolve_item(ret_ty), writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -91,14 +103,14 @@ impl CSerialize for Function { ctx, writer, |(name, type_id), ctx, buf| { - type_id.serialize(ctx, buf)?; + type_id.serialize(ctx, ctx.resolve_item(type_id), buf)?; write!(buf, " {}", name).map_err(From::from) }, )?; writeln!(writer, ") asm(\"{}\");", wrap_name)?; // Write `ret_ty wrap_name(args) { return name(arg_names)' }` - ret_ty.serialize(ctx, writer)?; + ret_ty.serialize(ctx, ctx.resolve_item(ret_ty), writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -106,7 +118,7 @@ impl CSerialize for Function { ctx, writer, |(name, type_id), _, buf| { - type_id.serialize(ctx, buf)?; + type_id.serialize(ctx, ctx.resolve_item(type_id), buf)?; write!(buf, " {}", name).map_err(From::from) }, )?; @@ -124,9 +136,10 @@ impl CSerialize for TypeId { fn serialize( &self, ctx: &BindgenContext, + item: &Item, writer: &mut W, ) -> Result<(), CodegenError> { - ctx.resolve_type(*self).serialize(ctx, writer) + ctx.resolve_type(*self).serialize(ctx, item, writer) } } @@ -134,6 +147,7 @@ impl CSerialize for Type { fn serialize( &self, ctx: &BindgenContext, + item: &Item, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { @@ -153,10 +167,13 @@ impl CSerialize for Type { IntKind::LongLong => write!(writer, "long long")?, IntKind::ULongLong => write!(writer, "unsigned long long")?, int_kind => { - return Err(CodegenError::Serialize(format!( - "Cannot serialize integer kind {:?}", - int_kind - ))) + return Err(CodegenError::Serialize { + msg: format!( + "Cannot serialize integer kind {:?}", + int_kind + ), + loc: get_loc(item), + }) } }, TypeKind::Float(float_kind) => match float_kind { @@ -171,25 +188,37 @@ impl CSerialize for Type { FloatKind::LongDouble => write!(writer, "long double complex")?, FloatKind::Float128 => write!(writer, "__complex128")?, }, - TypeKind::Alias(type_id) => { type_id.serialize(ctx, writer) }?, + TypeKind::Alias(type_id) => { + type_id.serialize(ctx, ctx.resolve_item(type_id), writer)? + } TypeKind::TemplateAlias(type_id, params) => { - type_id.serialize(ctx, writer)?; + type_id.serialize(ctx, ctx.resolve_item(type_id), writer)?; write!(writer, "<")?; serialize_sep( ", ", params.iter(), ctx, writer, - TypeId::serialize, + |type_id, ctx, writer| { + type_id.serialize( + ctx, + ctx.resolve_item(type_id), + writer, + ) + }, )?; write!(writer, ">")? } TypeKind::Array(type_id, length) => { - type_id.serialize(ctx, writer)?; + type_id.serialize(ctx, ctx.resolve_item(type_id), writer)?; write!(writer, " [{}]", length)? } TypeKind::Function(signature) => { - signature.return_type().serialize(ctx, writer)?; + signature.return_type().serialize( + ctx, + ctx.resolve_item(signature.return_type()), + writer, + )?; write!(writer, " (")?; serialize_sep( ", ", @@ -197,7 +226,11 @@ impl CSerialize for Type { ctx, writer, |(name, type_id), ctx, buf| { - type_id.serialize(ctx, buf)?; + type_id.serialize( + ctx, + ctx.resolve_item(type_id), + buf, + )?; if let Some(name) = name { write!(buf, "{}", name)?; @@ -209,17 +242,17 @@ impl CSerialize for Type { write!(writer, ")")? } TypeKind::ResolvedTypeRef(type_id) => { - type_id.serialize(ctx, writer)? + type_id.serialize(ctx, ctx.resolve_item(type_id), writer)? } TypeKind::Pointer(type_id) => { - type_id.serialize(ctx, writer)?; + type_id.serialize(ctx, ctx.resolve_item(type_id), writer)?; write!(writer, "*")?; } ty => { - return Err(CodegenError::Serialize(format!( - "Cannot serialize type kind {:?}", - ty - ))) + return Err(CodegenError::Serialize { + msg: format!("Cannot serialize type kind {:?}", ty), + loc: get_loc(item), + }) } }; From 6721b968a94d204374c708486b485d3490ba9c6a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 13:17:05 -0500 Subject: [PATCH 25/37] fix test --- bindgen-tests/tests/expectations/tests/generated/extern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindgen-tests/tests/expectations/tests/generated/extern.c b/bindgen-tests/tests/expectations/tests/generated/extern.c index 5fbf1bdb7a..e978c381a9 100644 --- a/bindgen-tests/tests/expectations/tests/generated/extern.c +++ b/bindgen-tests/tests/expectations/tests/generated/extern.c @@ -3,4 +3,4 @@ int foo__extern() { return foo(); } int bar__extern() asm("bar__extern"); int bar__extern() { return bar(); } int takes_ptr__extern(int* arg) asm("takes_ptr__extern"); -int takes_ptr__extern(int*arg) { return takes_ptr(arg); } +int takes_ptr__extern(int* arg) { return takes_ptr(arg); } From ab6ea2554b5114d6eefd5b382f852f9732d15135 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 13:26:18 -0500 Subject: [PATCH 26/37] add support for Comp types --- bindgen/codegen/serialize.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 9ec8e4a357..6971f347c1 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -7,6 +7,8 @@ use crate::ir::function::{Function, FunctionKind}; use crate::ir::item::Item; use crate::ir::item_kind::ItemKind; use crate::ir::ty::{FloatKind, Type, TypeKind}; +use crate::ir::comp::CompKind; +use crate::ir::item::ItemCanonicalName; use super::CodegenError; @@ -248,6 +250,15 @@ impl CSerialize for Type { type_id.serialize(ctx, ctx.resolve_item(type_id), writer)?; write!(writer, "*")?; } + TypeKind::Comp(comp_info) => { + 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), From bc7f6bff7531b0c8743f2b4eca3f42c66640a228 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 13:27:55 -0500 Subject: [PATCH 27/37] run rustfmt --- bindgen/codegen/serialize.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 6971f347c1..df9f2005ae 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -2,13 +2,13 @@ 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 crate::ir::comp::CompKind; -use crate::ir::item::ItemCanonicalName; use super::CodegenError; @@ -257,7 +257,6 @@ impl CSerialize for Type { CompKind::Struct => write!(writer, "struct {}", name)?, CompKind::Union => write!(writer, "union {}", name)?, }; - } ty => { return Err(CodegenError::Serialize { From e823b322978ae1349632f2fab3f6ae2b6c6b6745 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 13:29:47 -0500 Subject: [PATCH 28/37] support `char` --- bindgen/codegen/serialize.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index df9f2005ae..789020aeea 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -168,6 +168,7 @@ impl CSerialize for Type { 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!( From 0aafbee9b9caf8e90e8b7f9564c9e22418480387 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 13:56:30 -0500 Subject: [PATCH 29/37] add `Extra` associated type --- bindgen/codegen/mod.rs | 2 +- bindgen/codegen/serialize.rs | 51 ++++++++++++++++++++++-------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 4ff853248b..5340c4144e 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4585,7 +4585,7 @@ pub mod utils { for &id in &result.items_to_serialize { let item = context.resolve_item(id); - item.serialize(context, item, &mut code)?; + item.serialize(context, &(), &mut code)?; } std::fs::write(source_path, code)?; diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 789020aeea..7330d020fa 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -19,27 +19,31 @@ fn get_loc(item: &Item) -> String { } pub(crate) trait CSerialize { + type Extra; + fn serialize( &self, ctx: &BindgenContext, - item: &Item, + extra: &Self::Extra, writer: &mut W, ) -> Result<(), CodegenError>; } impl CSerialize for Item { + type Extra = (); + fn serialize( &self, ctx: &BindgenContext, - item: &Item, + (): &Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { - ItemKind::Function(func) => func.serialize(ctx, item, writer), + ItemKind::Function(func) => func.serialize(ctx, self, writer), kind => { return Err(CodegenError::Serialize { msg: format!("Cannot serialize item kind {:?}", kind), - loc: get_loc(item), + loc: get_loc(self), }); } } @@ -47,10 +51,12 @@ impl CSerialize for Item { } impl CSerialize for Function { + type Extra = Item; + fn serialize( &self, ctx: &BindgenContext, - item: &Item, + item: &Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { if self.kind() != FunctionKind::Function { @@ -97,7 +103,7 @@ impl CSerialize for Function { let ret_ty = signature.return_type(); // Write `ret_ty wrap_name(args) asm("wrap_name");` - ret_ty.serialize(ctx, ctx.resolve_item(ret_ty), writer)?; + ret_ty.serialize(ctx, &(), writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -105,14 +111,14 @@ impl CSerialize for Function { ctx, writer, |(name, type_id), ctx, buf| { - type_id.serialize(ctx, ctx.resolve_item(type_id), buf)?; + type_id.serialize(ctx, &(), buf)?; write!(buf, " {}", name).map_err(From::from) }, )?; writeln!(writer, ") asm(\"{}\");", wrap_name)?; // Write `ret_ty wrap_name(args) { return name(arg_names)' }` - ret_ty.serialize(ctx, ctx.resolve_item(ret_ty), writer)?; + ret_ty.serialize(ctx, &(), writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -120,7 +126,7 @@ impl CSerialize for Function { ctx, writer, |(name, type_id), _, buf| { - type_id.serialize(ctx, ctx.resolve_item(type_id), buf)?; + type_id.serialize(ctx, &(), buf)?; write!(buf, " {}", name).map_err(From::from) }, )?; @@ -135,21 +141,26 @@ impl CSerialize for Function { } impl CSerialize for TypeId { + type Extra = (); + fn serialize( &self, ctx: &BindgenContext, - item: &Item, + (): &Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { - ctx.resolve_type(*self).serialize(ctx, item, writer) + let item = ctx.resolve_item(*self); + item.expect_type().serialize(ctx, item, writer) } } impl CSerialize for Type { + type Extra = Item; + fn serialize( &self, ctx: &BindgenContext, - item: &Item, + item: &Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { @@ -192,10 +203,10 @@ impl CSerialize for Type { FloatKind::Float128 => write!(writer, "__complex128")?, }, TypeKind::Alias(type_id) => { - type_id.serialize(ctx, ctx.resolve_item(type_id), writer)? + type_id.serialize(ctx, &(), writer)? } TypeKind::TemplateAlias(type_id, params) => { - type_id.serialize(ctx, ctx.resolve_item(type_id), writer)?; + type_id.serialize(ctx, &(), writer)?; write!(writer, "<")?; serialize_sep( ", ", @@ -205,7 +216,7 @@ impl CSerialize for Type { |type_id, ctx, writer| { type_id.serialize( ctx, - ctx.resolve_item(type_id), + &(), writer, ) }, @@ -213,13 +224,13 @@ impl CSerialize for Type { write!(writer, ">")? } TypeKind::Array(type_id, length) => { - type_id.serialize(ctx, ctx.resolve_item(type_id), writer)?; + type_id.serialize(ctx, &(), writer)?; write!(writer, " [{}]", length)? } TypeKind::Function(signature) => { signature.return_type().serialize( ctx, - ctx.resolve_item(signature.return_type()), + &(), writer, )?; write!(writer, " (")?; @@ -231,7 +242,7 @@ impl CSerialize for Type { |(name, type_id), ctx, buf| { type_id.serialize( ctx, - ctx.resolve_item(type_id), + &(), buf, )?; @@ -245,10 +256,10 @@ impl CSerialize for Type { write!(writer, ")")? } TypeKind::ResolvedTypeRef(type_id) => { - type_id.serialize(ctx, ctx.resolve_item(type_id), writer)? + type_id.serialize(ctx, &(), writer)? } TypeKind::Pointer(type_id) => { - type_id.serialize(ctx, ctx.resolve_item(type_id), writer)?; + type_id.serialize(ctx, &(), writer)?; write!(writer, "*")?; } TypeKind::Comp(comp_info) => { From 58f740d887180d3bcc1e383d12c32119dbf85fe2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 15:44:57 -0500 Subject: [PATCH 30/37] add proper support for functions --- bindgen-integration/build.rs | 12 +- bindgen-integration/src/lib.rs | 10 ++ .../generated/{extern.c => wrap_static_fns.c} | 0 .../expectations/tests/wrap-static-fns.rs | 10 ++ bindgen-tests/tests/headers/wrap-static-fns.h | 8 ++ bindgen-tests/tests/tests.rs | 10 +- bindgen/codegen/mod.rs | 2 +- bindgen/codegen/serialize.rs | 108 ++++++++++-------- 8 files changed, 99 insertions(+), 61 deletions(-) rename bindgen-tests/tests/expectations/tests/generated/{extern.c => wrap_static_fns.c} (100%) diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index 00deb6f132..3cc0edb99b 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -224,22 +224,24 @@ fn setup_wrap_static_fns_test() { .header(input_header_file_path_str) .parse_callbacks(Box::new(CargoCallbacks)) .wrap_static_fns(true) - .wrap_static_fns_path(out_path.join("extern").display().to_string()) + .wrap_static_fns_path( + out_path.join("wrap_static_fns").display().to_string(), + ) .generate() .expect("Unable to generate bindings"); - println!("cargo:rustc-link-lib=static=extern"); // tell cargo to link libextern + println!("cargo:rustc-link-lib=static=wrap_static_fns"); // tell cargo to link libextern println!("bindings generated: {}", bindings); - let obj_path = out_path.join("extern.o"); - let lib_path = out_path.join("libextern.a"); + let obj_path = out_path.join("wrap_static_fns.o"); + let lib_path = out_path.join("libwrap_static_fns.a"); // build the external files to check if they work let clang_output = std::process::Command::new("clang") .arg("-c") .arg("-o") .arg(&obj_path) - .arg(out_path.join("extern.c")) + .arg(out_path.join("wrap_static_fns.c")) .arg("-include") .arg(input_header_file_path) .output() diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 5c6f0c6018..609da3eff7 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -303,5 +303,15 @@ fn test_wrap_static_fns() { let t = extern_bindings::takes_ptr(&mut 1); assert_eq!(2, t); + + extern "C" fn function(x: i32) -> i32 { + x + 1 + } + + let p = extern_bindings::takes_fn_ptr(Some(function)); + assert_eq!(2, p); + + let f = extern_bindings::takes_fn(Some(function)); + assert_eq!(3, f); } } diff --git a/bindgen-tests/tests/expectations/tests/generated/extern.c b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c similarity index 100% rename from bindgen-tests/tests/expectations/tests/generated/extern.c rename to bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c diff --git a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs index 01fef831c0..651543d907 100644 --- a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs +++ b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs @@ -17,3 +17,13 @@ extern "C" { #[link_name = "\u{1}takes_ptr__extern"] pub fn takes_ptr(arg: *mut ::std::os::raw::c_int) -> ::std::os::raw::c_int; } +extern "C" { + #[link_name = "\u{1}takes_fn_ptr__extern"] + pub fn takes_fn_ptr( + f: ::std::option::Option< + unsafe extern "C" fn( + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + ) -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/headers/wrap-static-fns.h b/bindgen-tests/tests/headers/wrap-static-fns.h index 0f4b36f9f3..f502a5ffe3 100644 --- a/bindgen-tests/tests/headers/wrap-static-fns.h +++ b/bindgen-tests/tests/headers/wrap-static-fns.h @@ -13,3 +13,11 @@ inline int baz() { static inline int takes_ptr(int* arg) { return *arg + 1; } + +static inline int takes_fn_ptr(int (*f)(int)) { + return f(1); +} + +static inline int takes_fn(int (f)(int)) { + return f(2); +} diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index 85183acd97..e5cf5c5794 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -719,12 +719,12 @@ fn test_extern_generated_headers() { // This test is for testing diffs of the generated C source and header files // TODO: If another such feature is added, convert this test into a more generic // test that looks at `tests/headers/generated` directory. - let expect_path = - PathBuf::from("tests/expectations/tests/generated").join("extern"); + let expect_path = PathBuf::from("tests/expectations/tests/generated") + .join("wrap_static_fns"); println!("In path is ::: {}", expect_path.display()); let generated_path = - PathBuf::from(env::var("OUT_DIR").unwrap()).join("extern"); + PathBuf::from(env::var("OUT_DIR").unwrap()).join("wrap_static_fns"); println!("Out path is ::: {}", generated_path.display()); let _bindings = Builder::default() @@ -735,10 +735,10 @@ fn test_extern_generated_headers() { .expect("Failed to generate bindings"); let expected_c = fs::read_to_string(expect_path.with_extension("c")) - .expect("Could not read generated extern.c"); + .expect("Could not read generated wrap_static_fns.c"); let actual_c = fs::read_to_string(generated_path.with_extension("c")) - .expect("Could not read actual extern.c"); + .expect("Could not read actual wrap_static_fns.c"); if expected_c != actual_c { error_diff_mismatch( diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 5340c4144e..35f968569f 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4585,7 +4585,7 @@ pub mod utils { for &id in &result.items_to_serialize { let item = context.resolve_item(id); - item.serialize(context, &(), &mut code)?; + item.serialize(context, (), &mut code)?; } std::fs::write(source_path, code)?; diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 7330d020fa..c9ec113c6e 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -18,24 +18,24 @@ fn get_loc(item: &Item) -> String { .unwrap_or_else(|| "unknown".to_owned()) } -pub(crate) trait CSerialize { +pub(crate) trait CSerialize<'a, 'ctx> { type Extra; fn serialize( &self, - ctx: &BindgenContext, - extra: &Self::Extra, + ctx: &'ctx BindgenContext, + arg: Self::Extra, writer: &mut W, ) -> Result<(), CodegenError>; } -impl CSerialize for Item { +impl<'a, 'ctx> CSerialize<'a, 'ctx> for Item { type Extra = (); fn serialize( &self, - ctx: &BindgenContext, - (): &Self::Extra, + ctx: &'ctx BindgenContext, + (): Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { @@ -50,13 +50,13 @@ impl CSerialize for Item { } } -impl CSerialize for Function { - type Extra = Item; +impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { + type Extra = &'a Item; fn serialize( &self, - ctx: &BindgenContext, - item: &Self::Extra, + ctx: &'ctx BindgenContext, + item: Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { if self.kind() != FunctionKind::Function { @@ -103,7 +103,7 @@ impl CSerialize for Function { let ret_ty = signature.return_type(); // Write `ret_ty wrap_name(args) asm("wrap_name");` - ret_ty.serialize(ctx, &(), writer)?; + ret_ty.serialize(ctx, &mut None, writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -111,14 +111,16 @@ impl CSerialize for Function { ctx, writer, |(name, type_id), ctx, buf| { - type_id.serialize(ctx, &(), buf)?; - write!(buf, " {}", name).map_err(From::from) + let mut name = Some(name.as_str()); + dbg!(&name); + type_id.serialize(ctx, &mut name, buf)?; + Ok(()) }, )?; writeln!(writer, ") asm(\"{}\");", wrap_name)?; // Write `ret_ty wrap_name(args) { return name(arg_names)' }` - ret_ty.serialize(ctx, &(), writer)?; + ret_ty.serialize(ctx, &mut None, writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -126,8 +128,9 @@ impl CSerialize for Function { ctx, writer, |(name, type_id), _, buf| { - type_id.serialize(ctx, &(), buf)?; - write!(buf, " {}", name).map_err(From::from) + let mut name = Some(name.as_str()); + type_id.serialize(ctx, &mut name, buf)?; + Ok(()) }, )?; write!(writer, ") {{ return {}(", name)?; @@ -140,27 +143,28 @@ impl CSerialize for Function { } } -impl CSerialize for TypeId { - type Extra = (); +impl<'a> CSerialize<'a, 'a> for TypeId { + type Extra = &'a mut Option<&'a str>; fn serialize( &self, - ctx: &BindgenContext, - (): &Self::Extra, + ctx: &'a BindgenContext, + arg: Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { let item = ctx.resolve_item(*self); - item.expect_type().serialize(ctx, item, writer) + dbg!(&arg); + item.expect_type().serialize(ctx, (item, arg), writer) } } -impl CSerialize for Type { - type Extra = Item; +impl<'a> CSerialize<'a, 'a> for Type { + type Extra = (&'a Item, &'a mut Option<&'a str>); fn serialize( &self, - ctx: &BindgenContext, - item: &Self::Extra, + ctx: &'a BindgenContext, + (item, arg): Self::Extra, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { @@ -203,10 +207,10 @@ impl CSerialize for Type { FloatKind::Float128 => write!(writer, "__complex128")?, }, TypeKind::Alias(type_id) => { - type_id.serialize(ctx, &(), writer)? + type_id.serialize(ctx, &mut None, writer)? } TypeKind::TemplateAlias(type_id, params) => { - type_id.serialize(ctx, &(), writer)?; + type_id.serialize(ctx, &mut None, writer)?; write!(writer, "<")?; serialize_sep( ", ", @@ -214,53 +218,53 @@ impl CSerialize for Type { ctx, writer, |type_id, ctx, writer| { - type_id.serialize( - ctx, - &(), - writer, - ) + type_id.serialize(ctx, &mut None, writer) }, )?; write!(writer, ">")? } TypeKind::Array(type_id, length) => { - type_id.serialize(ctx, &(), writer)?; + type_id.serialize(ctx, &mut None, writer)?; write!(writer, " [{}]", length)? } TypeKind::Function(signature) => { - signature.return_type().serialize( - ctx, - &(), - writer, - )?; + signature.return_type().serialize(ctx, &mut None, writer)?; + dbg!(&arg); + + if let Some(name) = arg.take() { + write!(writer, " ({})", name)?; + } + write!(writer, " (")?; serialize_sep( ", ", signature.argument_types().iter(), ctx, writer, - |(name, type_id), ctx, buf| { - type_id.serialize( - ctx, - &(), - buf, - )?; - - if let Some(name) = name { - write!(buf, "{}", name)?; + |(arg, type_id), ctx, buf| { + let mut name = None; + if let Some(arg) = arg { + name = Some(arg.as_str()); } + type_id.serialize(ctx, &mut name, buf)?; + Ok(()) }, )?; write!(writer, ")")? } TypeKind::ResolvedTypeRef(type_id) => { - type_id.serialize(ctx, &(), writer)? + return type_id.serialize(ctx, arg, writer); } TypeKind::Pointer(type_id) => { - type_id.serialize(ctx, &(), writer)?; - write!(writer, "*")?; + let mut name = "*".to_owned(); + if let Some(arg) = arg { + name += arg; + } + type_id.serialize(ctx, &mut Some(name.as_str()), writer)?; + + return Ok(()); } TypeKind::Comp(comp_info) => { let name = item.canonical_name(ctx); @@ -278,6 +282,10 @@ impl CSerialize for Type { } }; + if let Some(arg) = arg { + write!(writer, " {}", arg)?; + } + Ok(()) } } From affcb2f426a88789e152ee162f2823d30045a14d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 15:53:46 -0500 Subject: [PATCH 31/37] fix tests and remove dbg --- .../tests/generated/wrap_static_fns.c | 8 ++++++-- .../expectations/tests/wrap-static-fns.rs | 10 ++++++++++ bindgen-tests/tests/tests.rs | 2 +- bindgen/codegen/serialize.rs | 20 +++---------------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c index e978c381a9..26e15e3951 100644 --- a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c +++ b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c @@ -2,5 +2,9 @@ int foo__extern() asm("foo__extern"); int foo__extern() { return foo(); } int bar__extern() asm("bar__extern"); int bar__extern() { return bar(); } -int takes_ptr__extern(int* arg) asm("takes_ptr__extern"); -int takes_ptr__extern(int* arg) { return takes_ptr(arg); } +int takes_ptr__extern(int *arg) asm("takes_ptr__extern"); +int takes_ptr__extern(int *arg) { return takes_ptr(arg); } +int takes_fn_ptr__extern(int (*f) (int)) asm("takes_fn_ptr__extern"); +int takes_fn_ptr__extern(int (*f) (int)) { return takes_fn_ptr(f); } +int takes_fn__extern(int (f) (int)) asm("takes_fn__extern"); +int takes_fn__extern(int (f) (int)) { return takes_fn(f); } diff --git a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs index 651543d907..f486d59f68 100644 --- a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs +++ b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs @@ -27,3 +27,13 @@ extern "C" { >, ) -> ::std::os::raw::c_int; } +extern "C" { + #[link_name = "\u{1}takes_fn__extern"] + pub fn takes_fn( + f: ::std::option::Option< + unsafe extern "C" fn( + arg1: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + ) -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index e5cf5c5794..ed8566c607 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -715,7 +715,7 @@ fn commandline_multiple_headers() { } #[test] -fn test_extern_generated_headers() { +fn test_wrap_static_fns() { // This test is for testing diffs of the generated C source and header files // TODO: If another such feature is added, convert this test into a more generic // test that looks at `tests/headers/generated` directory. diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index c9ec113c6e..f57f34c228 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -111,10 +111,7 @@ impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { ctx, writer, |(name, type_id), ctx, buf| { - let mut name = Some(name.as_str()); - dbg!(&name); - type_id.serialize(ctx, &mut name, buf)?; - Ok(()) + type_id.serialize(ctx, &mut Some(name.as_str()), buf) }, )?; writeln!(writer, ") asm(\"{}\");", wrap_name)?; @@ -128,9 +125,7 @@ impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { ctx, writer, |(name, type_id), _, buf| { - let mut name = Some(name.as_str()); - type_id.serialize(ctx, &mut name, buf)?; - Ok(()) + type_id.serialize(ctx, &mut Some(name.as_str()), buf) }, )?; write!(writer, ") {{ return {}(", name)?; @@ -153,7 +148,6 @@ impl<'a> CSerialize<'a, 'a> for TypeId { writer: &mut W, ) -> Result<(), CodegenError> { let item = ctx.resolve_item(*self); - dbg!(&arg); item.expect_type().serialize(ctx, (item, arg), writer) } } @@ -229,7 +223,6 @@ impl<'a> CSerialize<'a, 'a> for Type { } TypeKind::Function(signature) => { signature.return_type().serialize(ctx, &mut None, writer)?; - dbg!(&arg); if let Some(name) = arg.take() { write!(writer, " ({})", name)?; @@ -242,14 +235,7 @@ impl<'a> CSerialize<'a, 'a> for Type { ctx, writer, |(arg, type_id), ctx, buf| { - let mut name = None; - if let Some(arg) = arg { - name = Some(arg.as_str()); - } - - type_id.serialize(ctx, &mut name, buf)?; - - Ok(()) + type_id.serialize(ctx, &mut arg.as_ref().map(|a| a.as_str()), buf) }, )?; write!(writer, ")")? From 4819ea40a575c32db77efb2e02d1fca2d2d99197 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 15:53:57 -0500 Subject: [PATCH 32/37] run rustfmt --- bindgen/codegen/serialize.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index f57f34c228..0c084923cd 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -235,7 +235,11 @@ impl<'a> CSerialize<'a, 'a> for Type { ctx, writer, |(arg, type_id), ctx, buf| { - type_id.serialize(ctx, &mut arg.as_ref().map(|a| a.as_str()), buf) + type_id.serialize( + ctx, + &mut arg.as_ref().map(|a| a.as_str()), + buf, + ) }, )?; write!(writer, ")")? From 7b8fe72f3cbbfcdfbd43fb4a3bae49df1e1ec275 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 16:27:12 -0500 Subject: [PATCH 33/37] handle type aliases --- bindgen-integration/src/lib.rs | 11 +++++++---- .../expectations/tests/generated/wrap_static_fns.c | 2 ++ .../tests/expectations/tests/wrap-static-fns.rs | 7 +++++++ bindgen-tests/tests/headers/wrap-static-fns.h | 6 ++++++ bindgen/codegen/serialize.rs | 6 +++++- 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 609da3eff7..f5c0c20680 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -308,10 +308,13 @@ fn test_wrap_static_fns() { x + 1 } - let p = extern_bindings::takes_fn_ptr(Some(function)); - assert_eq!(2, p); + let tp = extern_bindings::takes_fn_ptr(Some(function)); + assert_eq!(2, tp); - let f = extern_bindings::takes_fn(Some(function)); - assert_eq!(3, f); + let tf = extern_bindings::takes_fn(Some(function)); + assert_eq!(3, tf); + + let ta = extern_bindings::takes_alias(Some(function)); + assert_eq!(4, ta); } } diff --git a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c index 26e15e3951..02f3ec16c4 100644 --- a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c +++ b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c @@ -8,3 +8,5 @@ int takes_fn_ptr__extern(int (*f) (int)) asm("takes_fn_ptr__extern"); int takes_fn_ptr__extern(int (*f) (int)) { return takes_fn_ptr(f); } int takes_fn__extern(int (f) (int)) asm("takes_fn__extern"); int takes_fn__extern(int (f) (int)) { return takes_fn(f); } +int takes_alias__extern(func f) asm("takes_alias__extern"); +int takes_alias__extern(func f) { return takes_alias(f); } diff --git a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs index f486d59f68..02454e3167 100644 --- a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs +++ b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs @@ -37,3 +37,10 @@ extern "C" { >, ) -> ::std::os::raw::c_int; } +pub type func = ::std::option::Option< + unsafe extern "C" fn(arg1: ::std::os::raw::c_int) -> ::std::os::raw::c_int, +>; +extern "C" { + #[link_name = "\u{1}takes_alias__extern"] + pub fn takes_alias(f: func) -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/headers/wrap-static-fns.h b/bindgen-tests/tests/headers/wrap-static-fns.h index f502a5ffe3..ff37cf4ce7 100644 --- a/bindgen-tests/tests/headers/wrap-static-fns.h +++ b/bindgen-tests/tests/headers/wrap-static-fns.h @@ -21,3 +21,9 @@ static inline int takes_fn_ptr(int (*f)(int)) { static inline int takes_fn(int (f)(int)) { return f(2); } + +typedef int (func)(int); + +static inline int takes_alias(func f) { + return f(3); +} diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 0c084923cd..e358ad2b19 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -201,7 +201,11 @@ impl<'a> CSerialize<'a, 'a> for Type { FloatKind::Float128 => write!(writer, "__complex128")?, }, TypeKind::Alias(type_id) => { - type_id.serialize(ctx, &mut None, writer)? + if let Some(name) = self.name() { + write!(writer, "{}", name)?; + } else { + return type_id.serialize(ctx, arg, writer); + } } TypeKind::TemplateAlias(type_id, params) => { type_id.serialize(ctx, &mut None, writer)?; From 7698c71a61bfce80643d0e504cd09689ba130635 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 17:36:55 -0500 Subject: [PATCH 34/37] handle constness --- bindgen-integration/src/lib.rs | 4 + .../tests/generated/wrap_static_fns.c | 2 + .../expectations/tests/wrap-static-fns.rs | 6 + bindgen-tests/tests/headers/wrap-static-fns.h | 4 + bindgen/codegen/mod.rs | 2 +- bindgen/codegen/serialize.rs | 234 +++++++++++------- 6 files changed, 156 insertions(+), 96 deletions(-) diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index f5c0c20680..e89351c3b3 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -316,5 +316,9 @@ fn test_wrap_static_fns() { let ta = extern_bindings::takes_alias(Some(function)); assert_eq!(4, ta); + + let tq = + extern_bindings::takes_qualified(&(&5 as *const _) as *const _); + assert_eq!(5, tq); } } diff --git a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c index 02f3ec16c4..c73d67e920 100644 --- a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c +++ b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c @@ -10,3 +10,5 @@ int takes_fn__extern(int (f) (int)) asm("takes_fn__extern"); int takes_fn__extern(int (f) (int)) { return takes_fn(f); } int takes_alias__extern(func f) asm("takes_alias__extern"); int takes_alias__extern(func f) { return takes_alias(f); } +int takes_qualified__extern(const int *const *arg) asm("takes_qualified__extern"); +int takes_qualified__extern(const int *const *arg) { return takes_qualified(arg); } diff --git a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs index 02454e3167..54ed9fd4dd 100644 --- a/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs +++ b/bindgen-tests/tests/expectations/tests/wrap-static-fns.rs @@ -44,3 +44,9 @@ extern "C" { #[link_name = "\u{1}takes_alias__extern"] pub fn takes_alias(f: func) -> ::std::os::raw::c_int; } +extern "C" { + #[link_name = "\u{1}takes_qualified__extern"] + pub fn takes_qualified( + arg: *const *const ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/headers/wrap-static-fns.h b/bindgen-tests/tests/headers/wrap-static-fns.h index ff37cf4ce7..8b90c7bc38 100644 --- a/bindgen-tests/tests/headers/wrap-static-fns.h +++ b/bindgen-tests/tests/headers/wrap-static-fns.h @@ -27,3 +27,7 @@ typedef int (func)(int); static inline int takes_alias(func f) { return f(3); } + +static inline int takes_qualified(const int *const *arg) { + return **arg; +} diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 35f968569f..a8abc215ce 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4585,7 +4585,7 @@ pub mod utils { for &id in &result.items_to_serialize { let item = context.resolve_item(id); - item.serialize(context, (), &mut code)?; + item.serialize(context, (), &mut vec![], &mut code)?; } std::fs::write(source_path, code)?; diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index e358ad2b19..6b92888561 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -18,28 +18,32 @@ fn get_loc(item: &Item) -> String { .unwrap_or_else(|| "unknown".to_owned()) } -pub(crate) trait CSerialize<'a, 'ctx> { +pub(crate) trait CSerialize<'a> { type Extra; fn serialize( &self, - ctx: &'ctx BindgenContext, - arg: Self::Extra, + ctx: &BindgenContext, + extra: Self::Extra, + stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError>; } -impl<'a, 'ctx> CSerialize<'a, 'ctx> for Item { +impl<'a> CSerialize<'a> for Item { type Extra = (); fn serialize( &self, - ctx: &'ctx BindgenContext, + ctx: &BindgenContext, (): Self::Extra, + stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { - ItemKind::Function(func) => func.serialize(ctx, self, writer), + ItemKind::Function(func) => { + func.serialize(ctx, self, stack, writer) + } kind => { return Err(CodegenError::Serialize { msg: format!("Cannot serialize item kind {:?}", kind), @@ -50,13 +54,14 @@ impl<'a, 'ctx> CSerialize<'a, 'ctx> for Item { } } -impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { +impl<'a> CSerialize<'a> for Function { type Extra = &'a Item; fn serialize( &self, - ctx: &'ctx BindgenContext, + ctx: &BindgenContext, item: Self::Extra, + stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { if self.kind() != FunctionKind::Function { @@ -103,7 +108,7 @@ impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { let ret_ty = signature.return_type(); // Write `ret_ty wrap_name(args) asm("wrap_name");` - ret_ty.serialize(ctx, &mut None, writer)?; + ret_ty.serialize(ctx, (), stack, writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -111,13 +116,13 @@ impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { ctx, writer, |(name, type_id), ctx, buf| { - type_id.serialize(ctx, &mut Some(name.as_str()), 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, &mut None, writer)?; + ret_ty.serialize(ctx, (), stack, writer)?; write!(writer, " {}(", wrap_name)?; serialize_sep( ", ", @@ -125,7 +130,7 @@ impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { ctx, writer, |(name, type_id), _, buf| { - type_id.serialize(ctx, &mut Some(name.as_str()), buf) + type_id.serialize(ctx, (), &mut vec![name.clone()], buf) }, )?; write!(writer, ") {{ return {}(", name)?; @@ -138,99 +143,129 @@ impl<'a, 'ctx> CSerialize<'a, 'ctx> for Function { } } -impl<'a> CSerialize<'a, 'a> for TypeId { - type Extra = &'a mut Option<&'a str>; +impl<'a> CSerialize<'a> for TypeId { + type Extra = (); fn serialize( &self, - ctx: &'a BindgenContext, - arg: Self::Extra, + ctx: &BindgenContext, + (): Self::Extra, + stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { let item = ctx.resolve_item(*self); - item.expect_type().serialize(ctx, (item, arg), writer) + item.expect_type().serialize(ctx, item, stack, writer) } } -impl<'a> CSerialize<'a, 'a> for Type { - type Extra = (&'a Item, &'a mut Option<&'a str>); +impl<'a> CSerialize<'a> for Type { + type Extra = &'a Item; fn serialize( &self, - ctx: &'a BindgenContext, - (item, arg): Self::Extra, + ctx: &BindgenContext, + item: Self::Extra, + stack: &mut Vec, writer: &mut W, ) -> Result<(), CodegenError> { match self.kind() { - TypeKind::Void => write!(writer, "void")?, - TypeKind::NullPtr => write!(writer, "nullptr_t")?, - TypeKind::Int(int_kind) => 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::Void => { + if self.is_const() { + write!(writer, "const ")?; } - }, - TypeKind::Float(float_kind) => 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) => 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")?, - }, + 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() { - write!(writer, "{}", name)?; + if self.is_const() { + write!(writer, "const {}", name)?; + } else { + write!(writer, "{}", name)?; + } } else { - return type_id.serialize(ctx, arg, writer); + type_id.serialize(ctx, (), stack, writer)?; } } - TypeKind::TemplateAlias(type_id, params) => { - type_id.serialize(ctx, &mut None, writer)?; - write!(writer, "<")?; - serialize_sep( - ", ", - params.iter(), - ctx, - writer, - |type_id, ctx, writer| { - type_id.serialize(ctx, &mut None, writer) - }, - )?; - write!(writer, ">")? - } TypeKind::Array(type_id, length) => { - type_id.serialize(ctx, &mut None, writer)?; + type_id.serialize(ctx, (), stack, writer)?; write!(writer, " [{}]", length)? } TypeKind::Function(signature) => { - signature.return_type().serialize(ctx, &mut None, writer)?; + if self.is_const() { + stack.push("const ".to_string()); + } - if let Some(name) = arg.take() { - write!(writer, " ({})", name)?; + 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( @@ -238,29 +273,35 @@ impl<'a> CSerialize<'a, 'a> for Type { signature.argument_types().iter(), ctx, writer, - |(arg, type_id), ctx, buf| { - type_id.serialize( - ctx, - &mut arg.as_ref().map(|a| a.as_str()), - buf, - ) + |(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) => { - return type_id.serialize(ctx, arg, writer); + if self.is_const() { + write!(writer, "const ")?; + } + type_id.serialize(ctx, (), stack, writer)? } TypeKind::Pointer(type_id) => { - let mut name = "*".to_owned(); - if let Some(arg) = arg { - name += arg; + if self.is_const() { + stack.push("*const ".to_owned()); + } else { + stack.push("*".to_owned()); } - type_id.serialize(ctx, &mut Some(name.as_str()), writer)?; - - return Ok(()); + 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() { @@ -276,8 +317,11 @@ impl<'a> CSerialize<'a, 'a> for Type { } }; - if let Some(arg) = arg { - write!(writer, " {}", arg)?; + if !stack.is_empty() { + write!(writer, " ")?; + while let Some(item) = stack.pop() { + write!(writer, "{}", item)?; + } } Ok(()) @@ -286,14 +330,14 @@ impl<'a> CSerialize<'a, 'a> for Type { fn serialize_sep< W: Write, - F: Fn(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>, + F: FnMut(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>, I: Iterator, >( sep: &'static str, mut iter: I, ctx: &BindgenContext, buf: &mut W, - f: F, + mut f: F, ) -> Result<(), CodegenError> { if let Some(item) = iter.next() { f(item, ctx, buf)?; From 9326863cbac20d81e67326a8a5fd32faf3984e9d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 2 Feb 2023 17:47:41 -0500 Subject: [PATCH 35/37] use void for empty args --- .../tests/generated/wrap_static_fns.c | 4 ++-- bindgen/codegen/serialize.rs | 22 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c index c73d67e920..22b2f67f75 100644 --- a/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c +++ b/bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c @@ -1,6 +1,6 @@ -int foo__extern() asm("foo__extern"); +int foo__extern(void) asm("foo__extern"); int foo__extern() { return foo(); } -int bar__extern() asm("bar__extern"); +int bar__extern(void) asm("bar__extern"); int bar__extern() { return bar(); } int takes_ptr__extern(int *arg) asm("takes_ptr__extern"); int takes_ptr__extern(int *arg) { return takes_ptr(arg); } diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 6b92888561..3403870ae7 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -110,15 +110,19 @@ impl<'a> CSerialize<'a> for Function { // Write `ret_ty wrap_name(args) asm("wrap_name");` ret_ty.serialize(ctx, (), stack, writer)?; write!(writer, " {}(", wrap_name)?; - serialize_sep( - ", ", - args.iter(), - ctx, - writer, - |(name, type_id), ctx, buf| { - type_id.serialize(ctx, (), &mut vec![name.clone()], buf) - }, - )?; + 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)' }` From 5a9e5ca5b6d06210ffe412a2f2fb11dac4d0bdcc Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 6 Feb 2023 11:54:46 -0500 Subject: [PATCH 36/37] pass amanfmt :trollface: --- bindgen/codegen/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index a8abc215ce..1a9946e1bd 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -329,7 +329,7 @@ impl<'a> CodegenResult<'a> { } /// Get the overload number for the given function name. Increments the - /// counter internally so the next time we ask for the loverload for this + /// counter internally so the next time we ask for the overload for this /// name, we get the incremented value, and so on. fn overload_number(&mut self, name: &str) -> u32 { let counter = self.overload_counters.entry(name.into()).or_insert(0); From 572d1a42b6c529c4d09732e7ede64e18c940d2b9 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 7 Feb 2023 09:55:26 -0500 Subject: [PATCH 37/37] some nits --- bindgen/codegen/mod.rs | 9 +++++---- bindgen/codegen/serialize.rs | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 1a9946e1bd..b6fb70eb01 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -4169,7 +4169,6 @@ impl CodeGenerator for Function { 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)); } @@ -4528,9 +4527,7 @@ pub(crate) fn codegen( result.push(dynamic_items_tokens); } - if !result.items_to_serialize.is_empty() { - utils::serialize_items(&result, context)?; - } + utils::serialize_items(&result, context)?; Ok(postprocessing::postprocessing( result.items, @@ -4557,6 +4554,10 @@ pub mod utils { result: &CodegenResult, context: &BindgenContext, ) -> Result<(), CodegenError> { + if result.items_to_serialize.is_empty() { + return Ok(()); + } + let path = context .options() .wrap_static_fns_path diff --git a/bindgen/codegen/serialize.rs b/bindgen/codegen/serialize.rs index 3403870ae7..217098e590 100644 --- a/bindgen/codegen/serialize.rs +++ b/bindgen/codegen/serialize.rs @@ -337,7 +337,7 @@ fn serialize_sep< F: FnMut(I::Item, &BindgenContext, &mut W) -> Result<(), CodegenError>, I: Iterator, >( - sep: &'static str, + sep: &str, mut iter: I, ctx: &BindgenContext, buf: &mut W, @@ -345,8 +345,9 @@ fn serialize_sep< ) -> Result<(), CodegenError> { if let Some(item) = iter.next() { f(item, ctx, buf)?; + let sep = sep.as_bytes(); for item in iter { - write!(buf, "{}", sep)?; + buf.write_all(sep)?; f(item, ctx, buf)?; } }