Skip to content

Commit 81e3df4

Browse files
author
thb@sb
authored
Add generated_link_name_override method for ParseCallbacks. (#2425)
* 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.
1 parent 9b6d3d9 commit 81e3df4

File tree

10 files changed

+166
-18
lines changed

10 files changed

+166
-18
lines changed

bindgen-cli/options.rs

+26
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ struct BindgenCommand {
305305
/// Require successful linkage to all functions in the library.
306306
#[arg(long)]
307307
dynamic_link_require_all: bool,
308+
/// Prefix the name of exported symbols.
309+
#[arg(long)]
310+
prefix_link_name: Option<String>,
308311
/// Makes generated bindings `pub` only for items if the items are publically accessible in C++.
309312
#[arg(long)]
310313
respect_cxx_access_specs: bool,
@@ -462,6 +465,7 @@ where
462465
wasm_import_module_name,
463466
dynamic_loading,
464467
dynamic_link_require_all,
468+
prefix_link_name,
465469
respect_cxx_access_specs,
466470
translate_enum_integer_types,
467471
c_naming,
@@ -868,6 +872,28 @@ where
868872
builder = builder.dynamic_link_require_all(true);
869873
}
870874

875+
if let Some(prefix_link_name) = prefix_link_name {
876+
#[derive(Debug)]
877+
struct PrefixLinkNameCallback {
878+
prefix: String,
879+
}
880+
881+
impl bindgen::callbacks::ParseCallbacks for PrefixLinkNameCallback {
882+
fn generated_link_name_override(
883+
&self,
884+
item_info: bindgen::callbacks::ItemInfo<'_>,
885+
) -> Option<String> {
886+
let mut prefix = self.prefix.clone();
887+
prefix.push_str(item_info.name);
888+
Some(prefix)
889+
}
890+
}
891+
892+
builder = builder.parse_callbacks(Box::new(PrefixLinkNameCallback {
893+
prefix: prefix_link_name,
894+
}))
895+
}
896+
871897
if respect_cxx_access_specs {
872898
builder = builder.respect_cxx_access_specs(true);
873899
}

bindgen-tests/tests/expectations/tests/prefix-link-name-c.rs

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/expectations/tests/prefix-link-name-cpp.rs

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// bindgen-parse-callbacks: prefix-link-name-foo_
2+
// bindgen-flags: --prefix-link-name foo_
3+
4+
int bar(void);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// bindgen-parse-callbacks: prefix-link-name-foo_
2+
// bindgen-flags: --prefix-link-name foo_
3+
4+
namespace baz {
5+
6+
int foo();
7+
8+
} // end namespace baz

bindgen-tests/tests/parse_callbacks/mod.rs

+29
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@ impl ParseCallbacks for RemovePrefixParseCallback {
3131
}
3232
}
3333

34+
#[derive(Debug)]
35+
pub struct PrefixLinkNameParseCallback {
36+
pub prefix: Option<String>,
37+
}
38+
39+
impl PrefixLinkNameParseCallback {
40+
pub fn new(prefix: &str) -> Self {
41+
PrefixLinkNameParseCallback {
42+
prefix: Some(prefix.to_string()),
43+
}
44+
}
45+
}
46+
47+
impl ParseCallbacks for PrefixLinkNameParseCallback {
48+
fn generated_link_name_override(
49+
&self,
50+
item_info: ItemInfo,
51+
) -> Option<String> {
52+
self.prefix
53+
.as_deref()
54+
.map(|prefix| format!("{}{}", prefix, item_info.name))
55+
}
56+
}
57+
3458
#[derive(Debug)]
3559
struct EnumVariantRename;
3660

@@ -76,6 +100,11 @@ pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
76100
.to_owned();
77101
let lnopc = RemovePrefixParseCallback::new(prefix.unwrap());
78102
Box::new(lnopc)
103+
} else if call_back.starts_with("prefix-link-name-") {
104+
let prefix =
105+
call_back.split("prefix-link-name-").last().to_owned();
106+
let plnpc = PrefixLinkNameParseCallback::new(prefix.unwrap());
107+
Box::new(plnpc)
79108
} else {
80109
panic!("Couldn't find name ParseCallbacks: {}", cb)
81110
}

bindgen/callbacks.rs

+9
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ pub trait ParseCallbacks: fmt::Debug {
4545
None
4646
}
4747

48+
/// This function will run for every extern variable and function. The returned value determines
49+
/// the link name in the bindings.
50+
fn generated_link_name_override(
51+
&self,
52+
_item_info: ItemInfo<'_>,
53+
) -> Option<String> {
54+
None
55+
}
56+
4857
/// The integer kind an integer macro should have, given a name and the
4958
/// value of that macro, or `None` if you want the default to be chosen.
5059
fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {

bindgen/codegen/mod.rs

+24-14
Original file line numberDiff line numberDiff line change
@@ -745,13 +745,18 @@ impl CodeGenerator for Var {
745745
}
746746
} else {
747747
// If necessary, apply a `#[link_name]` attribute
748-
let link_name = self.mangled_name().unwrap_or_else(|| self.name());
749-
if !utils::names_will_be_identical_after_mangling(
750-
&canonical_name,
751-
link_name,
752-
None,
753-
) {
748+
if let Some(link_name) = self.link_name() {
754749
attrs.push(attributes::link_name::<false>(link_name));
750+
} else {
751+
let link_name =
752+
self.mangled_name().unwrap_or_else(|| self.name());
753+
if !utils::names_will_be_identical_after_mangling(
754+
&canonical_name,
755+
link_name,
756+
None,
757+
) {
758+
attrs.push(attributes::link_name::<false>(link_name));
759+
}
755760
}
756761

757762
let maybe_mut = if self.is_const() {
@@ -4147,16 +4152,21 @@ impl CodeGenerator for Function {
41474152
}
41484153

41494154
let mut has_link_name_attr = false;
4150-
let link_name = mangled_name.unwrap_or(name);
4151-
if !is_dynamic_function &&
4152-
!utils::names_will_be_identical_after_mangling(
4153-
&canonical_name,
4154-
link_name,
4155-
Some(abi),
4156-
)
4157-
{
4155+
if let Some(link_name) = self.link_name() {
41584156
attributes.push(attributes::link_name::<false>(link_name));
41594157
has_link_name_attr = true;
4158+
} else {
4159+
let link_name = mangled_name.unwrap_or(name);
4160+
if !is_dynamic_function &&
4161+
!utils::names_will_be_identical_after_mangling(
4162+
&canonical_name,
4163+
link_name,
4164+
Some(abi),
4165+
)
4166+
{
4167+
attributes.push(attributes::link_name::<false>(link_name));
4168+
has_link_name_attr = true;
4169+
}
41604170
}
41614171

41624172
// Unfortunately this can't piggyback on the `attributes` list because

bindgen/ir/function.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ pub(crate) struct Function {
8282
/// The mangled name, that is, the symbol.
8383
mangled_name: Option<String>,
8484

85+
/// The link name. If specified, overwrite mangled_name.
86+
link_name: Option<String>,
87+
8588
/// The ID pointing to the current function signature.
8689
signature: TypeId,
8790

@@ -97,13 +100,15 @@ impl Function {
97100
pub(crate) fn new(
98101
name: String,
99102
mangled_name: Option<String>,
103+
link_name: Option<String>,
100104
signature: TypeId,
101105
kind: FunctionKind,
102106
linkage: Linkage,
103107
) -> Self {
104108
Function {
105109
name,
106110
mangled_name,
111+
link_name,
107112
signature,
108113
kind,
109114
linkage,
@@ -120,6 +125,11 @@ impl Function {
120125
self.mangled_name.as_deref()
121126
}
122127

128+
/// Get this function's link name.
129+
pub fn link_name(&self) -> Option<&str> {
130+
self.link_name.as_deref()
131+
}
132+
123133
/// Get this function's signature type.
124134
pub(crate) fn signature(&self) -> TypeId {
125135
self.signature
@@ -726,8 +736,21 @@ impl ClangSubItemParser for Function {
726736

727737
let mangled_name = cursor_mangling(context, &cursor);
728738

729-
let function =
730-
Self::new(name.clone(), mangled_name, sig, kind, linkage);
739+
let link_name = context.options().last_callback(|callbacks| {
740+
callbacks.generated_link_name_override(ItemInfo {
741+
name: name.as_str(),
742+
kind: ItemKind::Function,
743+
})
744+
});
745+
746+
let function = Self::new(
747+
name.clone(),
748+
mangled_name,
749+
link_name,
750+
sig,
751+
kind,
752+
linkage,
753+
);
731754

732755
Ok(ParseResult::New(function, Some(cursor)))
733756
}

bindgen/ir/var.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub(crate) struct Var {
3737
name: String,
3838
/// The mangled name of the variable.
3939
mangled_name: Option<String>,
40+
/// The link name of the variable.
41+
link_name: Option<String>,
4042
/// The type of the variable.
4143
ty: TypeId,
4244
/// The value of the variable, that needs to be suitable for `ty`.
@@ -50,6 +52,7 @@ impl Var {
5052
pub(crate) fn new(
5153
name: String,
5254
mangled_name: Option<String>,
55+
link_name: Option<String>,
5356
ty: TypeId,
5457
val: Option<VarType>,
5558
is_const: bool,
@@ -58,6 +61,7 @@ impl Var {
5861
Var {
5962
name,
6063
mangled_name,
64+
link_name,
6165
ty,
6266
val,
6367
is_const,
@@ -88,6 +92,11 @@ impl Var {
8892
pub(crate) fn mangled_name(&self) -> Option<&str> {
8993
self.mangled_name.as_deref()
9094
}
95+
96+
/// Get this variable's link name.
97+
pub fn link_name(&self) -> Option<&str> {
98+
self.link_name.as_deref()
99+
}
91100
}
92101

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

269278
Ok(ParseResult::New(
270-
Var::new(name, None, ty, Some(val), true),
279+
Var::new(name, None, None, ty, Some(val), true),
271280
Some(cursor),
272281
))
273282
}
@@ -291,6 +300,13 @@ impl ClangSubItemParser for Var {
291300
return Err(ParseError::Continue);
292301
}
293302

303+
let link_name = ctx.options().last_callback(|callbacks| {
304+
callbacks.generated_link_name_override(ItemInfo {
305+
name: name.as_str(),
306+
kind: ItemKind::Var,
307+
})
308+
});
309+
294310
let ty = cursor.cur_type();
295311

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

362378
let mangling = cursor_mangling(ctx, &cursor);
363-
let var = Var::new(name, mangling, ty, value, is_const);
379+
let var =
380+
Var::new(name, mangling, link_name, ty, value, is_const);
364381

365382
Ok(ParseResult::New(var, Some(cursor)))
366383
}

0 commit comments

Comments
 (0)