Skip to content

Commit

Permalink
Add a C naming option (#2045)
Browse files Browse the repository at this point in the history
Closes #2045.
Fixes #1252.
  • Loading branch information
Bobo1239 authored and emilio committed Apr 30, 2021
1 parent 425a146 commit 4943058
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 1 deletion.
24 changes: 23 additions & 1 deletion src/ir/item.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<T> IsOpaque for T
Expand Down
17 changes: 17 additions & 0 deletions src/lib.rs
Expand Up @@ -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());
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/options.rs
Expand Up @@ -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);

Expand Down Expand Up @@ -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))
Expand Down
92 changes: 92 additions & 0 deletions 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::<struct_a>(),
4usize,
concat!("Size of: ", stringify!(struct_a))
);
assert_eq!(
::std::mem::align_of::<struct_a>(),
4usize,
concat!("Alignment of ", stringify!(struct_a))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<struct_a>())).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::<union_b>(),
4usize,
concat!("Size of: ", stringify!(union_b))
);
assert_eq!(
::std::mem::align_of::<union_b>(),
4usize,
concat!("Alignment of ", stringify!(union_b))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<union_b>())).a as *const _ as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(union_b),
"::",
stringify!(a)
)
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<union_b>())).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);
}
19 changes: 19 additions & 0 deletions 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) {}

0 comments on commit 4943058

Please sign in to comment.