diff --git a/src/ir/item.rs b/src/ir/item.rs index ffb52664ac..9375c79871 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -4,7 +4,7 @@ use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME}; use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult}; use super::annotations::Annotations; use super::comment; -use super::comp::MethodKind; +use super::comp::{CompKind, MethodKind}; use super::context::{BindgenContext, ItemId, PartialType, TypeId}; use super::derive::{ CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq, @@ -904,6 +904,12 @@ impl Item { names.push(base_name); } + if ctx.options().c_naming { + if let Some(prefix) = self.c_naming_prefix() { + names.insert(0, prefix.to_string()); + } + } + let name = names.join("_"); let name = if opt.user_mangled == UserMangled::Yes { @@ -1054,6 +1060,22 @@ impl Item { path.reverse(); path } + + /// Returns a prefix for the canonical name when C naming is enabled. + fn c_naming_prefix(&self) -> Option<&str> { + if let ItemKind::Type(typ) = &self.kind { + match typ.kind() { + TypeKind::Comp(comp_info) => match comp_info.kind() { + CompKind::Struct => Some("struct"), + CompKind::Union => Some("union"), + }, + TypeKind::Enum(_) => Some("enum"), + _ => None, + } + } else { + None + } + } } impl IsOpaque for T diff --git a/src/lib.rs b/src/lib.rs index 58c99c8dec..1ac053b7f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -558,6 +558,10 @@ impl Builder { output_vector.push("--translate-enum-integer-types".into()); } + if self.options.c_naming { + output_vector.push("--c-naming".into()); + } + // Add clang arguments output_vector.push("--".into()); @@ -1616,6 +1620,15 @@ impl Builder { self.options.translate_enum_integer_types = doit; self } + + /// Generate types with C style naming. + /// + /// This will add prefixes to the generated type names. For example instead of a struct `A` we + /// will generate struct `struct_A`. Currently applies to structs, unions, and enums. + pub fn c_naming(mut self, doit: bool) -> Self { + self.options.c_naming = doit; + self + } } /// Configuration options for generated bindings. @@ -1921,6 +1934,9 @@ struct BindgenOptions { /// Always translate enum integer types to native Rust integer types. translate_enum_integer_types: bool, + + /// Generate types with C style naming. + c_naming: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -2062,6 +2078,7 @@ impl Default for BindgenOptions { dynamic_link_require_all: false, respect_cxx_access_specs: false, translate_enum_integer_types: false, + c_naming: false, } } } diff --git a/src/options.rs b/src/options.rs index ff2d42827e..cbdc945ebb 100644 --- a/src/options.rs +++ b/src/options.rs @@ -513,6 +513,9 @@ where Arg::with_name("translate-enum-integer-types") .long("translate-enum-integer-types") .help("Always translate enum integer types to native Rust integer types."), + Arg::with_name("c-naming") + .long("c-naming") + .help("Generate types with C style naming."), ]) // .args() .get_matches_from(args); @@ -953,6 +956,10 @@ where builder = builder.translate_enum_integer_types(true); } + if matches.is_present("c-naming") { + builder = builder.c_naming(true); + } + let verbose = matches.is_present("verbose"); Ok((builder, output, verbose)) diff --git a/tests/expectations/tests/c_naming.rs b/tests/expectations/tests/c_naming.rs new file mode 100644 index 0000000000..041e75ea70 --- /dev/null +++ b/tests/expectations/tests/c_naming.rs @@ -0,0 +1,92 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct struct_a { + pub a: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_struct_a() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(struct_a)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(struct_a)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).a as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(struct_a), + "::", + stringify!(a) + ) + ); +} +pub type a = *const struct_a; +#[repr(C)] +#[derive(Copy, Clone)] +pub union union_b { + pub a: ::std::os::raw::c_int, + pub b: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_union_b() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(union_b)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(union_b)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).a as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(union_b), + "::", + stringify!(a) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).b as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(union_b), + "::", + stringify!(b) + ) + ); +} +impl Default for union_b { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +pub type b = union_b; +pub const enum_c_A: enum_c = 0; +pub type enum_c = ::std::os::raw::c_uint; +extern "C" { + pub fn takes_a(arg: a); +} +extern "C" { + pub fn takes_b(arg: b); +} +extern "C" { + pub fn takes_c(arg: enum_c); +} diff --git a/tests/headers/c_naming.h b/tests/headers/c_naming.h new file mode 100644 index 0000000000..fd84c271fa --- /dev/null +++ b/tests/headers/c_naming.h @@ -0,0 +1,19 @@ +// bindgen-flags: --c-naming + +typedef const struct a { + int a; +} *a; + +union b { + int a; + int b; +}; +typedef union b b; + +enum c { + A, +}; + +void takes_a(a arg) {} +void takes_b(b arg) {} +void takes_c(enum c arg) {}