Skip to content

Commit

Permalink
Add generated_link_name_override method for ParseCallbacks. (#2425)
Browse files Browse the repository at this point in the history
* Add `generated_link_name_override` method for `ParseCallbacks`.

`generated_link_name_override` lets the developer choose the link name for
a symbol.

If a link name is specified, the attribute `#[link_name = "\u{1}VALUE"]` will
be set, overriding any other potential link name, including the mangled name.

This commit also adds an option to the bindgen cli called `prefix-link-name`,
to prefix the link name of exported symbols.

I think this should properly solve #1375.

* Fix expectation file for `prefix-link-name-c`.

* Fix expectation file for `prefix-link-name-cpp`

* Add a new `parse_callbacks` callback to solve the roundtrip test.
  • Loading branch information
thb-sb committed Mar 19, 2023
1 parent 9b6d3d9 commit 81e3df4
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 18 deletions.
26 changes: 26 additions & 0 deletions bindgen-cli/options.rs
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
@@ -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
@@ -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
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
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
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
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
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

0 comments on commit 81e3df4

Please sign in to comment.