@@ -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 {}
20312044impl 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 ,
0 commit comments