Skip to content

Commit 32fbc13

Browse files
committed
add option to deduplicate extern blocks
1 parent 5b1652c commit 32fbc13

File tree

4 files changed

+120
-3
lines changed

4 files changed

+120
-3
lines changed

src/lib.rs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,10 @@ impl Builder {
592592
output_vector.push("--sort-semantically".into());
593593
}
594594

595+
if self.options.deduplicate_extern_blocks {
596+
output_vector.push("--deduplicate-extern-blocks".into());
597+
}
598+
595599
// Add clang arguments
596600

597601
output_vector.push("--".into());
@@ -1481,14 +1485,20 @@ impl Builder {
14811485
self
14821486
}
14831487

1484-
/// If true, enables the sorting of the output in a predefined manner
1488+
/// If true, enables the sorting of the output in a predefined manner.
14851489
///
14861490
/// TODO: Perhaps move the sorting order out into a config
14871491
pub fn sort_semantically(mut self, doit: bool) -> Self {
14881492
self.options.sort_semantically = doit;
14891493
self
14901494
}
14911495

1496+
/// If true, deduplicates extern blocks.
1497+
pub fn deduplicate_extern_blocks(mut self, doit: bool) -> Self {
1498+
self.options.deduplicate_extern_blocks = doit;
1499+
self
1500+
}
1501+
14921502
/// Generate the Rust bindings using the options built up thus far.
14931503
pub fn generate(mut self) -> Result<Bindings, BindgenError> {
14941504
// Add any extra arguments from the environment to the clang command line.
@@ -2019,8 +2029,11 @@ struct BindgenOptions {
20192029
/// Emit vtable functions.
20202030
vtable_generation: bool,
20212031

2022-
/// Sort the code generation
2032+
/// Sort the code generation.
20232033
sort_semantically: bool,
2034+
2035+
/// Deduplicate `extern` blocks.
2036+
deduplicate_extern_blocks: bool,
20242037
}
20252038

20262039
/// TODO(emilio): This is sort of a lie (see the error message that results from
@@ -2031,7 +2044,7 @@ impl ::std::panic::UnwindSafe for BindgenOptions {}
20312044
impl BindgenOptions {
20322045
/// Whether any of the enabled options requires `syn`.
20332046
fn require_syn(&self) -> bool {
2034-
self.sort_semantically
2047+
self.sort_semantically || self.deduplicate_extern_blocks
20352048
}
20362049

20372050
fn build(&mut self) {
@@ -2175,6 +2188,7 @@ impl Default for BindgenOptions {
21752188
force_explicit_padding: false,
21762189
vtable_generation: false,
21772190
sort_semantically: false,
2191+
deduplicate_extern_blocks: false,
21782192
}
21792193
}
21802194
}
@@ -2480,6 +2494,59 @@ impl Bindings {
24802494
.unwrap()
24812495
.1;
24822496

2497+
if options.deduplicate_extern_blocks {
2498+
// Here we will store all the items after deduplication.
2499+
let mut items = Vec::new();
2500+
2501+
// Keep all the extern blocks in a different `Vec` for faster search.
2502+
let mut foreign_mods = Vec::<syn::ItemForeignMod>::new();
2503+
for item in syn_parsed_items {
2504+
match item {
2505+
syn::Item::ForeignMod(syn::ItemForeignMod {
2506+
attrs,
2507+
abi,
2508+
brace_token,
2509+
items: foreign_items,
2510+
}) => {
2511+
let mut exists = false;
2512+
for foreign_mod in &mut foreign_mods {
2513+
// Check if there is a extern block with the same ABI and
2514+
// attributes.
2515+
if foreign_mod.attrs == attrs &&
2516+
foreign_mod.abi == abi
2517+
{
2518+
// Merge the items of the two blocks.
2519+
foreign_mod
2520+
.items
2521+
.extend_from_slice(&foreign_items);
2522+
exists = true;
2523+
break;
2524+
}
2525+
}
2526+
// If no existing extern block had the same ABI and attributes, store
2527+
// it.
2528+
if !exists {
2529+
foreign_mods.push(syn::ItemForeignMod {
2530+
attrs,
2531+
abi,
2532+
brace_token,
2533+
items: foreign_items,
2534+
});
2535+
}
2536+
}
2537+
// If the item is not an extern block, we don't have to do anything.
2538+
_ => items.push(item),
2539+
}
2540+
}
2541+
2542+
// Move all the extern blocks alongiside the rest of the items.
2543+
for foreign_mod in foreign_mods {
2544+
items.push(syn::Item::ForeignMod(foreign_mod));
2545+
}
2546+
2547+
syn_parsed_items = items;
2548+
}
2549+
24832550
if options.sort_semantically {
24842551
syn_parsed_items.sort_by_key(|item| match item {
24852552
syn::Item::Type(_) => 0,

src/options.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,9 @@ where
518518
Arg::new("sort-semantically")
519519
.long("sort-semantically")
520520
.help("Enables sorting of code generation in a predefined manner."),
521+
Arg::new("deduplicate-extern-blocks")
522+
.long("deduplicate-extern-blocks")
523+
.help("Deduplicates extern blocks."),
521524
Arg::new("V")
522525
.long("version")
523526
.help("Prints the version, and exits"),
@@ -1007,5 +1010,9 @@ where
10071010
builder = builder.sort_semantically(true);
10081011
}
10091012

1013+
if matches.is_present("deduplicate-extern-blocks") {
1014+
builder = builder.deduplicate_extern_blocks(true);
1015+
}
1016+
10101017
Ok((builder, output, verbose))
10111018
}

tests/expectations/tests/deduplicate-extern-blocks.rs

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// bindgen-flags: --deduplicate-extern-blocks -- --target=x86_64-unknown-linux
2+
int foo();
3+
typedef struct Point {
4+
int x;
5+
} Point;
6+
int bar();

0 commit comments

Comments
 (0)