Skip to content

Commit afbc4d8

Browse files
committed
Generate extern wrappers for inlined functions
If bindgen finds an inlined function and the `--generate-extern-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 additional 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 rust-lang#1090.
1 parent bca47cd commit afbc4d8

File tree

9 files changed

+487
-9
lines changed

9 files changed

+487
-9
lines changed

bindgen-cli/options.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,18 @@ struct BindgenCommand {
353353
/// Derive custom traits on a `union`. The <CUSTOM> value must be of the shape <REGEX>=<DERIVE> where <DERIVE> is a coma-separated list of derive macros.
354354
#[arg(long, value_name = "CUSTOM")]
355355
with_derive_custom_union: Vec<String>,
356+
/// Generate extern wrappers for inlined functions
357+
#[arg(long)]
358+
generate_extern_functions: bool,
359+
/// 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.
360+
#[arg(long, value_name = "FILENAME")]
361+
extern_functions_file_name: Option<String>,
362+
#[arg(long, value_name = "DIRECTORY")]
363+
/// Sets the directory path where any extra files must be created due to the presence of inlined functions.
364+
extern_functions_directory: Option<String>,
365+
/// Sets the suffix added to the extern wrapper functions generated for inlined functions.
366+
#[arg(long, value_name = "SUFFIX")]
367+
extern_function_suffix: Option<String>,
356368
/// Prints the version, and exits
357369
#[arg(short = 'V', long)]
358370
version: bool,
@@ -473,6 +485,10 @@ where
473485
with_derive_custom_struct,
474486
with_derive_custom_enum,
475487
with_derive_custom_union,
488+
generate_extern_functions,
489+
extern_functions_file_name,
490+
extern_functions_directory,
491+
extern_function_suffix,
476492
version,
477493
clang_args,
478494
} = command;
@@ -978,5 +994,21 @@ where
978994
}
979995
}
980996

997+
if generate_extern_functions {
998+
builder = builder.generate_extern_functions(true);
999+
}
1000+
1001+
if let Some(file_name) = extern_functions_file_name {
1002+
builder = builder.extern_functions_file_name(file_name);
1003+
}
1004+
1005+
if let Some(directory) = extern_functions_directory {
1006+
builder = builder.extern_functions_directory(directory);
1007+
}
1008+
1009+
if let Some(suffix) = extern_function_suffix {
1010+
builder = builder.extern_function_suffix(suffix);
1011+
}
1012+
9811013
Ok((builder, output, verbose))
9821014
}

bindgen-tests/tests/expectations/tests/generate-extern-functions.rs

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// bindgen-flags: --generate-extern-functions
2+
3+
static inline int foo() {
4+
return 0;
5+
}
6+
static int bar() {
7+
return 1;
8+
}
9+
inline int baz() {
10+
return 2;
11+
}

bindgen/codegen/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4002,9 +4002,8 @@ impl CodeGenerator for Function {
40024002

40034003
// We can't currently do anything with Internal functions so just
40044004
// avoid generating anything for them.
4005-
match self.linkage() {
4006-
Linkage::Internal => return None,
4007-
Linkage::External => {}
4005+
if matches!(self.linkage(), Linkage::Internal) {
4006+
return None;
40084007
}
40094008

40104009
// Pure virtual methods have no actual symbol, so we can't generate
@@ -4114,6 +4113,7 @@ impl CodeGenerator for Function {
41144113
write!(&mut canonical_name, "{}", times_seen).unwrap();
41154114
}
41164115

4116+
let mut has_link_name_attr = false;
41174117
let link_name = mangled_name.unwrap_or(name);
41184118
if !is_dynamic_function &&
41194119
!utils::names_will_be_identical_after_mangling(
@@ -4123,6 +4123,7 @@ impl CodeGenerator for Function {
41234123
)
41244124
{
41254125
attributes.push(attributes::link_name(link_name));
4126+
has_link_name_attr = true;
41264127
}
41274128

41284129
// Unfortunately this can't piggyback on the `attributes` list because
@@ -4133,6 +4134,20 @@ impl CodeGenerator for Function {
41334134
quote! { #[link(wasm_import_module = #name)] }
41344135
});
41354136

4137+
if ctx.options().generate_extern_functions.is_second_run() {
4138+
if let Some(name) = canonical_name.strip_suffix(
4139+
ctx.options()
4140+
.extern_function_suffix
4141+
.as_deref()
4142+
.unwrap_or(crate::DEFAULT_EXTERN_FUNCTION_SUFFIX),
4143+
) {
4144+
if !has_link_name_attr {
4145+
attributes.push(attributes::link_name(&canonical_name));
4146+
}
4147+
canonical_name = name.to_owned();
4148+
}
4149+
}
4150+
41364151
let ident = ctx.rust_ident(canonical_name);
41374152
let tokens = quote! {
41384153
#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};
@@ -477,6 +478,9 @@ pub struct BindgenContext {
477478

478479
/// The set of warnings raised during binding generation.
479480
warnings: Vec<String>,
481+
482+
/// C items that need to be serialized to an extra header file.
483+
pub(crate) c_items: Vec<CItem>,
480484
}
481485

482486
/// A traversal of allowlisted items.
@@ -593,6 +597,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
593597
has_type_param_in_array: None,
594598
has_float: None,
595599
warnings: Vec::new(),
600+
c_items: Vec::new(),
596601
}
597602
}
598603

bindgen/ir/function.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use super::traversal::{EdgeKind, Trace, Tracer};
88
use super::ty::TypeKind;
99
use crate::callbacks::{ItemInfo, ItemKind};
1010
use crate::clang::{self, Attribute};
11+
use crate::ir::serialize::CItem;
1112
use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
1213
use clang_sys::{self, CXCallingConv};
1314
use proc_macro2;
@@ -679,9 +680,12 @@ impl ClangSubItemParser for Function {
679680
.definition()
680681
.map_or(false, |x| x.is_inlined_function())
681682
{
682-
if !context.options().generate_inline_functions {
683+
if !(context.options().generate_inline_functions ||
684+
context.options().generate_extern_functions.is_true())
685+
{
683686
return Err(ParseError::Continue);
684687
}
688+
685689
if cursor.is_deleted_function() {
686690
return Err(ParseError::Continue);
687691
}
@@ -728,6 +732,16 @@ impl ClangSubItemParser for Function {
728732

729733
let function =
730734
Self::new(name, mangled_name, sig, comment, kind, linkage);
735+
736+
if matches!(linkage, Linkage::Internal) &&
737+
context.options().generate_extern_functions.is_true()
738+
{
739+
match CItem::from_function(&function, context) {
740+
Ok(c_item) => context.c_items.push(c_item),
741+
Err(err) => warn!("Serialization failed: {:?}", err),
742+
}
743+
}
744+
731745
Ok(ParseResult::New(function, Some(cursor)))
732746
}
733747
}

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)