Skip to content

Commit 364755c

Browse files
committed
add option to deduplicate extern blocks
1 parent 6dfc3e7 commit 364755c

File tree

4 files changed

+142
-23
lines changed

4 files changed

+142
-23
lines changed

src/lib.rs

Lines changed: 92 additions & 23 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
@@ -2170,6 +2183,7 @@ impl Default for BindgenOptions {
21702183
force_explicit_padding: false,
21712184
vtable_generation: false,
21722185
sort_semantically: false,
2186+
deduplicate_extern_blocks: false,
21732187
}
21742188
}
21752189
}
@@ -2455,7 +2469,7 @@ impl Bindings {
24552469

24562470
let (items, options, warnings) = codegen::codegen(context);
24572471

2458-
if options.sort_semantically {
2472+
if options.sort_semantically || options.deduplicate_extern_blocks {
24592473
let module_wrapped_tokens =
24602474
quote!(mod wrapper_for_sorting_hack { #( #items )* });
24612475

@@ -2475,26 +2489,81 @@ impl Bindings {
24752489
.unwrap()
24762490
.1;
24772491

2478-
syn_parsed_items.sort_by_key(|item| match item {
2479-
syn::Item::Type(_) => 0,
2480-
syn::Item::Struct(_) => 1,
2481-
syn::Item::Const(_) => 2,
2482-
syn::Item::Fn(_) => 3,
2483-
syn::Item::Enum(_) => 4,
2484-
syn::Item::Union(_) => 5,
2485-
syn::Item::Static(_) => 6,
2486-
syn::Item::Trait(_) => 7,
2487-
syn::Item::TraitAlias(_) => 8,
2488-
syn::Item::Impl(_) => 9,
2489-
syn::Item::Mod(_) => 10,
2490-
syn::Item::Use(_) => 11,
2491-
syn::Item::Verbatim(_) => 12,
2492-
syn::Item::ExternCrate(_) => 13,
2493-
syn::Item::ForeignMod(_) => 14,
2494-
syn::Item::Macro(_) => 15,
2495-
syn::Item::Macro2(_) => 16,
2496-
_ => 18,
2497-
});
2492+
if options.deduplicate_extern_blocks {
2493+
// Here we will store all the items after deduplication.
2494+
let mut items = Vec::new();
2495+
2496+
// Keep all the extern blocks in a different `Vec` for faster search.
2497+
let mut foreign_mods = Vec::<syn::ItemForeignMod>::new();
2498+
for item in syn_parsed_items {
2499+
match item {
2500+
syn::Item::ForeignMod(syn::ItemForeignMod {
2501+
attrs,
2502+
abi,
2503+
brace_token,
2504+
items: foreign_items,
2505+
}) => {
2506+
let mut exists = false;
2507+
for foreign_mod in &mut foreign_mods {
2508+
// Check if there is a extern block with the same ABI and
2509+
// attributes.
2510+
if foreign_mod.attrs == attrs &&
2511+
foreign_mod.abi == abi
2512+
{
2513+
// Merge the items of the two blocks.
2514+
foreign_mod
2515+
.items
2516+
.extend_from_slice(&foreign_items);
2517+
exists = true;
2518+
break;
2519+
}
2520+
}
2521+
// If no existing extern block had the same ABI and attributes, store
2522+
// it.
2523+
if !exists {
2524+
foreign_mods.push(syn::ItemForeignMod {
2525+
attrs,
2526+
abi,
2527+
brace_token,
2528+
items: foreign_items,
2529+
});
2530+
}
2531+
}
2532+
// If the item is not an extern block, we don't have to do anything.
2533+
_ => items.push(item),
2534+
}
2535+
}
2536+
2537+
// Move all the extern blocks alongiside the rest of the items.
2538+
for foreign_mod in foreign_mods {
2539+
items.push(syn::Item::ForeignMod(foreign_mod));
2540+
}
2541+
2542+
syn_parsed_items = items;
2543+
}
2544+
2545+
if options.sort_semantically {
2546+
syn_parsed_items.sort_by_key(|item| match item {
2547+
syn::Item::Type(_) => 0,
2548+
syn::Item::Struct(_) => 1,
2549+
syn::Item::Const(_) => 2,
2550+
syn::Item::Fn(_) => 3,
2551+
syn::Item::Enum(_) => 4,
2552+
syn::Item::Union(_) => 5,
2553+
syn::Item::Static(_) => 6,
2554+
syn::Item::Trait(_) => 7,
2555+
syn::Item::TraitAlias(_) => 8,
2556+
syn::Item::Impl(_) => 9,
2557+
syn::Item::Mod(_) => 10,
2558+
syn::Item::Use(_) => 11,
2559+
syn::Item::Verbatim(_) => 12,
2560+
syn::Item::ExternCrate(_) => 13,
2561+
syn::Item::ForeignMod(_) => 14,
2562+
syn::Item::Macro(_) => 15,
2563+
syn::Item::Macro2(_) => 16,
2564+
_ => 18,
2565+
});
2566+
}
24982567

24992568
let synful_items = syn_parsed_items
25002569
.into_iter()

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)