Skip to content

Commit 039d7d0

Browse files
committed
Generate extern wrappers for inlined functions
If bindgen finds an inlined function and the `--generate-inline-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes #1090.
1 parent e8ffb42 commit 039d7d0

File tree

7 files changed

+379
-10
lines changed

7 files changed

+379
-10
lines changed

bindgen-cli/options.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,18 @@ where
574574
.value_name("override")
575575
.multiple_occurrences(true)
576576
.number_of_values(1),
577+
Arg::new("extern-functions-file-name")
578+
.long("extern-functions-file-name")
579+
.help("Sets the name of the header and source code files that would be created if any extern wrapper functions must be generated due to the presence of inlined functions.")
580+
.takes_value(true),
581+
Arg::new("extern-functions-directory")
582+
.long("extern-functions-directory")
583+
.help("Sets the directory path where any extra files must be created due to the presence of inlined functions.")
584+
.takes_value(true),
585+
Arg::new("extern-function-suffix")
586+
.long("extern-function-suffix")
587+
.help("Sets the suffix added to the extern wrapper functions generated for inlined functions.")
588+
.takes_value(true),
577589
Arg::new("V")
578590
.long("version")
579591
.help("Prints the version, and exits"),
@@ -1106,5 +1118,17 @@ where
11061118
}
11071119
}
11081120

1121+
if let Some(file_name) = matches.value_of("extern-functions-file-name") {
1122+
builder = builder.extern_functions_file_name(file_name);
1123+
}
1124+
1125+
if let Some(directory) = matches.value_of("extern-functions-directory") {
1126+
builder = builder.extern_functions_directory(directory);
1127+
}
1128+
1129+
if let Some(suffix) = matches.value_of("extern-function-suffix") {
1130+
builder = builder.extern_function_suffix(suffix);
1131+
}
1132+
11091133
Ok((builder, output, verbose))
11101134
}

bindgen/codegen/mod.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ use crate::ir::derive::{
3232
};
3333
use crate::ir::dot;
3434
use crate::ir::enum_ty::{Enum, EnumVariant, EnumVariantValue};
35-
use crate::ir::function::{
36-
Abi, ClangAbi, Function, FunctionKind, FunctionSig, Linkage,
37-
};
35+
use crate::ir::function::{Abi, ClangAbi, Function, FunctionKind, FunctionSig};
3836
use crate::ir::int::IntKind;
3937
use crate::ir::item::{IsOpaque, Item, ItemCanonicalName, ItemCanonicalPath};
4038
use crate::ir::item_kind::ItemKind;
@@ -4045,9 +4043,8 @@ impl CodeGenerator for Function {
40454043

40464044
// We can't currently do anything with Internal functions so just
40474045
// avoid generating anything for them.
4048-
match self.linkage() {
4049-
Linkage::Internal => return None,
4050-
Linkage::External => {}
4046+
if self.is_inlined() {
4047+
return None;
40514048
}
40524049

40534050
// Pure virtual methods have no actual symbol, so we can't generate
@@ -4150,13 +4147,14 @@ impl CodeGenerator for Function {
41504147
abi => abi,
41514148
};
41524149

4153-
// Handle overloaded functions by giving each overload its own unique
4150+
// Handle overloaded functions by giving each overload its own uniq_ue
41544151
// suffix.
41554152
let times_seen = result.overload_number(&canonical_name);
41564153
if times_seen > 0 {
41574154
write!(&mut canonical_name, "{}", times_seen).unwrap();
41584155
}
41594156

4157+
let mut has_link_name_attr = false;
41604158
let link_name = mangled_name.unwrap_or(name);
41614159
if !is_dynamic_function &&
41624160
!utils::names_will_be_identical_after_mangling(
@@ -4166,6 +4164,7 @@ impl CodeGenerator for Function {
41664164
)
41674165
{
41684166
attributes.push(attributes::link_name(link_name));
4167+
has_link_name_attr = true;
41694168
}
41704169

41714170
// Unfortunately this can't piggyback on the `attributes` list because
@@ -4176,6 +4175,18 @@ impl CodeGenerator for Function {
41764175
quote! { #[link(wasm_import_module = #name)] }
41774176
});
41784177

4178+
if let Some(name) = canonical_name.strip_suffix(
4179+
ctx.options()
4180+
.extern_function_suffix
4181+
.as_deref()
4182+
.unwrap_or(crate::DEFAULT_EXTERN_FUNCTION_SUFFIX),
4183+
) {
4184+
if !has_link_name_attr {
4185+
attributes.push(attributes::link_name(&canonical_name));
4186+
}
4187+
canonical_name = name.to_owned();
4188+
}
4189+
41794190
let ident = ctx.rust_ident(canonical_name);
41804191
let tokens = quote! {
41814192
#wasm_link_attribute

bindgen/ir/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use super::int::IntKind;
1616
use super::item::{IsOpaque, Item, ItemAncestors, ItemSet};
1717
use super::item_kind::ItemKind;
1818
use super::module::{Module, ModuleKind};
19+
use super::serialize::CItem;
1920
use super::template::{TemplateInstantiation, TemplateParameters};
2021
use super::traversal::{self, Edge, ItemTraversal};
2122
use super::ty::{FloatKind, Type, TypeKind};
@@ -461,6 +462,9 @@ pub struct BindgenContext {
461462

462463
/// The set of warnings raised during binding generation.
463464
warnings: Vec<String>,
465+
466+
/// C items that need to be serialized to an extra header file.
467+
pub(crate) c_items: Vec<CItem>,
464468
}
465469

466470
/// A traversal of allowlisted items.
@@ -576,6 +580,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
576580
has_type_param_in_array: None,
577581
has_float: None,
578582
warnings: Vec::new(),
583+
c_items: Vec::new(),
579584
}
580585
}
581586

bindgen/ir/function.rs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use super::item::Item;
77
use super::traversal::{EdgeKind, Trace, Tracer};
88
use super::ty::TypeKind;
99
use crate::clang::{self, Attribute};
10+
use crate::ir::serialize::CItem;
1011
use crate::parse::{
1112
ClangItemParser, ClangSubItemParser, ParseError, ParseResult,
1213
};
@@ -95,6 +96,9 @@ pub struct Function {
9596

9697
/// The linkage of the function.
9798
linkage: Linkage,
99+
100+
/// Whether this function is inlined or not.
101+
is_inlined: bool,
98102
}
99103

100104
impl Function {
@@ -106,6 +110,7 @@ impl Function {
106110
comment: Option<String>,
107111
kind: FunctionKind,
108112
linkage: Linkage,
113+
is_inlined: bool,
109114
) -> Self {
110115
Function {
111116
name,
@@ -114,6 +119,7 @@ impl Function {
114119
comment,
115120
kind,
116121
linkage,
122+
is_inlined,
117123
}
118124
}
119125

@@ -146,6 +152,11 @@ impl Function {
146152
pub fn linkage(&self) -> Linkage {
147153
self.linkage
148154
}
155+
156+
/// Whether this function is inlined or not.
157+
pub fn is_inlined(&self) -> bool {
158+
self.is_inlined
159+
}
149160
}
150161

151162
impl DotAttributes for Function {
@@ -675,7 +686,9 @@ impl ClangSubItemParser for Function {
675686
return Err(ParseError::Continue);
676687
}
677688

678-
if cursor.is_inlined_function() {
689+
let is_inlined = cursor.is_inlined_function();
690+
691+
if is_inlined {
679692
if !context.options().generate_inline_functions {
680693
return Err(ParseError::Continue);
681694
}
@@ -721,8 +734,22 @@ impl ClangSubItemParser for Function {
721734
let mangled_name = cursor_mangling(context, &cursor);
722735
let comment = cursor.raw_comment();
723736

724-
let function =
725-
Self::new(name, mangled_name, sig, comment, kind, linkage);
737+
let function = Self::new(
738+
name,
739+
mangled_name,
740+
sig,
741+
comment,
742+
kind,
743+
linkage,
744+
is_inlined,
745+
);
746+
747+
if is_inlined {
748+
context
749+
.c_items
750+
.push(CItem::from_function(&function, context));
751+
}
752+
726753
Ok(ParseResult::New(function, Some(cursor)))
727754
}
728755
}

bindgen/ir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub mod item_kind;
1818
pub mod layout;
1919
pub mod module;
2020
pub mod objc;
21+
pub(crate) mod serialize;
2122
pub mod template;
2223
pub mod traversal;
2324
pub mod ty;

0 commit comments

Comments
 (0)