Skip to content

Add generated_link_name_override method for ParseCallbacks. #2425

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from Mar 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions bindgen-cli/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ struct BindgenCommand {
/// Require successful linkage to all functions in the library.
#[arg(long)]
dynamic_link_require_all: bool,
/// Prefix the name of exported symbols.
#[arg(long)]
prefix_link_name: Option<String>,
/// Makes generated bindings `pub` only for items if the items are publically accessible in C++.
#[arg(long)]
respect_cxx_access_specs: bool,
Expand Down Expand Up @@ -462,6 +465,7 @@ where
wasm_import_module_name,
dynamic_loading,
dynamic_link_require_all,
prefix_link_name,
respect_cxx_access_specs,
translate_enum_integer_types,
c_naming,
Expand Down Expand Up @@ -868,6 +872,28 @@ where
builder = builder.dynamic_link_require_all(true);
}

if let Some(prefix_link_name) = prefix_link_name {
#[derive(Debug)]
struct PrefixLinkNameCallback {
prefix: String,
}

impl bindgen::callbacks::ParseCallbacks for PrefixLinkNameCallback {
fn generated_link_name_override(
&self,
item_info: bindgen::callbacks::ItemInfo<'_>,
) -> Option<String> {
let mut prefix = self.prefix.clone();
prefix.push_str(item_info.name);
Some(prefix)
}
}

builder = builder.parse_callbacks(Box::new(PrefixLinkNameCallback {
prefix: prefix_link_name,
}))
}

if respect_cxx_access_specs {
builder = builder.respect_cxx_access_specs(true);
}
Expand Down
11 changes: 11 additions & 0 deletions bindgen-tests/tests/expectations/tests/prefix-link-name-c.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions bindgen-tests/tests/expectations/tests/prefix-link-name-cpp.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions bindgen-tests/tests/headers/prefix-link-name-c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// bindgen-parse-callbacks: prefix-link-name-foo_
// bindgen-flags: --prefix-link-name foo_

int bar(void);
8 changes: 8 additions & 0 deletions bindgen-tests/tests/headers/prefix-link-name-cpp.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// bindgen-parse-callbacks: prefix-link-name-foo_
// bindgen-flags: --prefix-link-name foo_

namespace baz {

int foo();

} // end namespace baz
29 changes: 29 additions & 0 deletions bindgen-tests/tests/parse_callbacks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,30 @@ impl ParseCallbacks for RemovePrefixParseCallback {
}
}

#[derive(Debug)]
pub struct PrefixLinkNameParseCallback {
pub prefix: Option<String>,
}

impl PrefixLinkNameParseCallback {
pub fn new(prefix: &str) -> Self {
PrefixLinkNameParseCallback {
prefix: Some(prefix.to_string()),
}
}
}

impl ParseCallbacks for PrefixLinkNameParseCallback {
fn generated_link_name_override(
&self,
item_info: ItemInfo,
) -> Option<String> {
self.prefix
.as_deref()
.map(|prefix| format!("{}{}", prefix, item_info.name))
}
}

#[derive(Debug)]
struct EnumVariantRename;

Expand Down Expand Up @@ -76,6 +100,11 @@ pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
.to_owned();
let lnopc = RemovePrefixParseCallback::new(prefix.unwrap());
Box::new(lnopc)
} else if call_back.starts_with("prefix-link-name-") {
let prefix =
call_back.split("prefix-link-name-").last().to_owned();
let plnpc = PrefixLinkNameParseCallback::new(prefix.unwrap());
Box::new(plnpc)
} else {
panic!("Couldn't find name ParseCallbacks: {}", cb)
}
Expand Down
9 changes: 9 additions & 0 deletions bindgen/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ pub trait ParseCallbacks: fmt::Debug {
None
}

/// This function will run for every extern variable and function. The returned value determines
/// the link name in the bindings.
fn generated_link_name_override(
&self,
_item_info: ItemInfo<'_>,
) -> Option<String> {
None
}

/// The integer kind an integer macro should have, given a name and the
/// value of that macro, or `None` if you want the default to be chosen.
fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
Expand Down
38 changes: 24 additions & 14 deletions bindgen/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,13 +745,18 @@ impl CodeGenerator for Var {
}
} else {
// If necessary, apply a `#[link_name]` attribute
let link_name = self.mangled_name().unwrap_or_else(|| self.name());
if !utils::names_will_be_identical_after_mangling(
&canonical_name,
link_name,
None,
) {
if let Some(link_name) = self.link_name() {
attrs.push(attributes::link_name::<false>(link_name));
} else {
let link_name =
self.mangled_name().unwrap_or_else(|| self.name());
if !utils::names_will_be_identical_after_mangling(
&canonical_name,
link_name,
None,
) {
attrs.push(attributes::link_name::<false>(link_name));
}
}

let maybe_mut = if self.is_const() {
Expand Down Expand Up @@ -4147,16 +4152,21 @@ impl CodeGenerator for Function {
}

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(
&canonical_name,
link_name,
Some(abi),
)
{
if let Some(link_name) = self.link_name() {
attributes.push(attributes::link_name::<false>(link_name));
has_link_name_attr = true;
} else {
let link_name = mangled_name.unwrap_or(name);
if !is_dynamic_function &&
!utils::names_will_be_identical_after_mangling(
&canonical_name,
link_name,
Some(abi),
)
{
attributes.push(attributes::link_name::<false>(link_name));
has_link_name_attr = true;
}
}

// Unfortunately this can't piggyback on the `attributes` list because
Expand Down
27 changes: 25 additions & 2 deletions bindgen/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ pub(crate) struct Function {
/// The mangled name, that is, the symbol.
mangled_name: Option<String>,

/// The link name. If specified, overwrite mangled_name.
link_name: Option<String>,

/// The ID pointing to the current function signature.
signature: TypeId,

Expand All @@ -97,13 +100,15 @@ impl Function {
pub(crate) fn new(
name: String,
mangled_name: Option<String>,
link_name: Option<String>,
signature: TypeId,
kind: FunctionKind,
linkage: Linkage,
) -> Self {
Function {
name,
mangled_name,
link_name,
signature,
kind,
linkage,
Expand All @@ -120,6 +125,11 @@ impl Function {
self.mangled_name.as_deref()
}

/// Get this function's link name.
pub fn link_name(&self) -> Option<&str> {
self.link_name.as_deref()
}

/// Get this function's signature type.
pub(crate) fn signature(&self) -> TypeId {
self.signature
Expand Down Expand Up @@ -726,8 +736,21 @@ impl ClangSubItemParser for Function {

let mangled_name = cursor_mangling(context, &cursor);

let function =
Self::new(name.clone(), mangled_name, sig, kind, linkage);
let link_name = context.options().last_callback(|callbacks| {
callbacks.generated_link_name_override(ItemInfo {
name: name.as_str(),
kind: ItemKind::Function,
})
});

let function = Self::new(
name.clone(),
mangled_name,
link_name,
sig,
kind,
linkage,
);

Ok(ParseResult::New(function, Some(cursor)))
}
Expand Down
21 changes: 19 additions & 2 deletions bindgen/ir/var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub(crate) struct Var {
name: String,
/// The mangled name of the variable.
mangled_name: Option<String>,
/// The link name of the variable.
link_name: Option<String>,
/// The type of the variable.
ty: TypeId,
/// The value of the variable, that needs to be suitable for `ty`.
Expand All @@ -50,6 +52,7 @@ impl Var {
pub(crate) fn new(
name: String,
mangled_name: Option<String>,
link_name: Option<String>,
ty: TypeId,
val: Option<VarType>,
is_const: bool,
Expand All @@ -58,6 +61,7 @@ impl Var {
Var {
name,
mangled_name,
link_name,
ty,
val,
is_const,
Expand Down Expand Up @@ -88,6 +92,11 @@ impl Var {
pub(crate) fn mangled_name(&self) -> Option<&str> {
self.mangled_name.as_deref()
}

/// Get this variable's link name.
pub fn link_name(&self) -> Option<&str> {
self.link_name.as_deref()
}
}

impl DotAttributes for Var {
Expand Down Expand Up @@ -267,7 +276,7 @@ impl ClangSubItemParser for Var {
let ty = Item::builtin_type(type_kind, true, ctx);

Ok(ParseResult::New(
Var::new(name, None, ty, Some(val), true),
Var::new(name, None, None, ty, Some(val), true),
Some(cursor),
))
}
Expand All @@ -291,6 +300,13 @@ impl ClangSubItemParser for Var {
return Err(ParseError::Continue);
}

let link_name = ctx.options().last_callback(|callbacks| {
callbacks.generated_link_name_override(ItemInfo {
name: name.as_str(),
kind: ItemKind::Var,
})
});

let ty = cursor.cur_type();

// TODO(emilio): do we have to special-case constant arrays in
Expand Down Expand Up @@ -360,7 +376,8 @@ impl ClangSubItemParser for Var {
};

let mangling = cursor_mangling(ctx, &cursor);
let var = Var::new(name, mangling, ty, value, is_const);
let var =
Var::new(name, mangling, link_name, ty, value, is_const);

Ok(ParseResult::New(var, Some(cursor)))
}
Expand Down