Skip to content

Commit

Permalink
Add option to deduplicate extern blocks (#2258)
Browse files Browse the repository at this point in the history
  • Loading branch information
pvdrz committed Sep 23, 2022
1 parent 04c0cd0 commit 4b006da
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 3 deletions.
73 changes: 70 additions & 3 deletions src/lib.rs
Expand Up @@ -615,6 +615,10 @@ impl Builder {
output_vector.push("--sort-semantically".into());
}

if self.options.merge_extern_blocks {
output_vector.push("--merge-extern-blocks".into());
}

// Add clang arguments

output_vector.push("--".into());
Expand Down Expand Up @@ -1542,14 +1546,20 @@ impl Builder {
self
}

/// If true, enables the sorting of the output in a predefined manner
/// If true, enables the sorting of the output in a predefined manner.
///
/// TODO: Perhaps move the sorting order out into a config
pub fn sort_semantically(mut self, doit: bool) -> Self {
self.options.sort_semantically = doit;
self
}

/// If true, merges extern blocks.
pub fn merge_extern_blocks(mut self, doit: bool) -> Self {
self.options.merge_extern_blocks = doit;
self
}

/// Generate the Rust bindings using the options built up thus far.
pub fn generate(mut self) -> Result<Bindings, BindgenError> {
// Add any extra arguments from the environment to the clang command line.
Expand Down Expand Up @@ -2095,8 +2105,11 @@ struct BindgenOptions {
/// Emit vtable functions.
vtable_generation: bool,

/// Sort the code generation
/// Sort the code generation.
sort_semantically: bool,

/// Deduplicate `extern` blocks.
merge_extern_blocks: bool,
}

/// TODO(emilio): This is sort of a lie (see the error message that results from
Expand All @@ -2107,7 +2120,7 @@ impl ::std::panic::UnwindSafe for BindgenOptions {}
impl BindgenOptions {
/// Whether any of the enabled options requires `syn`.
fn require_syn(&self) -> bool {
self.sort_semantically
self.sort_semantically || self.merge_extern_blocks
}

fn build(&mut self) {
Expand Down Expand Up @@ -2258,6 +2271,7 @@ impl Default for BindgenOptions {
force_explicit_padding: false,
vtable_generation: false,
sort_semantically: false,
merge_extern_blocks: false,
}
}
}
Expand Down Expand Up @@ -2563,6 +2577,59 @@ impl Bindings {
.unwrap()
.1;

if options.merge_extern_blocks {
// Here we will store all the items after deduplication.
let mut items = Vec::new();

// Keep all the extern blocks in a different `Vec` for faster search.
let mut foreign_mods = Vec::<syn::ItemForeignMod>::new();
for item in syn_parsed_items {
match item {
syn::Item::ForeignMod(syn::ItemForeignMod {
attrs,
abi,
brace_token,
items: foreign_items,
}) => {
let mut exists = false;
for foreign_mod in &mut foreign_mods {
// Check if there is a extern block with the same ABI and
// attributes.
if foreign_mod.attrs == attrs &&
foreign_mod.abi == abi
{
// Merge the items of the two blocks.
foreign_mod
.items
.extend_from_slice(&foreign_items);
exists = true;
break;
}
}
// If no existing extern block had the same ABI and attributes, store
// it.
if !exists {
foreign_mods.push(syn::ItemForeignMod {
attrs,
abi,
brace_token,
items: foreign_items,
});
}
}
// If the item is not an extern block, we don't have to do anything.
_ => items.push(item),
}
}

// Move all the extern blocks alongiside the rest of the items.
for foreign_mod in foreign_mods {
items.push(syn::Item::ForeignMod(foreign_mod));
}

syn_parsed_items = items;
}

if options.sort_semantically {
syn_parsed_items.sort_by_key(|item| match item {
syn::Item::Type(_) => 0,
Expand Down
7 changes: 7 additions & 0 deletions src/options.rs
Expand Up @@ -560,6 +560,9 @@ where
Arg::new("sort-semantically")
.long("sort-semantically")
.help("Enables sorting of code generation in a predefined manner."),
Arg::new("merge-extern-blocks")
.long("merge-extern-blocks")
.help("Deduplicates extern blocks."),
Arg::new("V")
.long("version")
.help("Prints the version, and exits"),
Expand Down Expand Up @@ -1076,5 +1079,9 @@ where
builder = builder.sort_semantically(true);
}

if matches.is_present("merge-extern-blocks") {
builder = builder.merge_extern_blocks(true);
}

Ok((builder, output, verbose))
}
37 changes: 37 additions & 0 deletions tests/expectations/tests/merge-extern-blocks.rs

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

6 changes: 6 additions & 0 deletions tests/headers/merge-extern-blocks.h
@@ -0,0 +1,6 @@
// bindgen-flags: --merge-extern-blocks -- --target=x86_64-unknown-linux
int foo();
typedef struct Point {
int x;
} Point;
int bar();

0 comments on commit 4b006da

Please sign in to comment.