@@ -592,6 +592,10 @@ impl Builder {
592
592
output_vector. push ( "--sort-semantically" . into ( ) ) ;
593
593
}
594
594
595
+ if self . options . deduplicate_extern_blocks {
596
+ output_vector. push ( "--deduplicate-extern-blocks" . into ( ) ) ;
597
+ }
598
+
595
599
// Add clang arguments
596
600
597
601
output_vector. push ( "--" . into ( ) ) ;
@@ -1481,14 +1485,20 @@ impl Builder {
1481
1485
self
1482
1486
}
1483
1487
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.
1485
1489
///
1486
1490
/// TODO: Perhaps move the sorting order out into a config
1487
1491
pub fn sort_semantically ( mut self , doit : bool ) -> Self {
1488
1492
self . options . sort_semantically = doit;
1489
1493
self
1490
1494
}
1491
1495
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
+
1492
1502
/// Generate the Rust bindings using the options built up thus far.
1493
1503
pub fn generate ( mut self ) -> Result < Bindings , BindgenError > {
1494
1504
// Add any extra arguments from the environment to the clang command line.
@@ -2019,8 +2029,11 @@ struct BindgenOptions {
2019
2029
/// Emit vtable functions.
2020
2030
vtable_generation : bool ,
2021
2031
2022
- /// Sort the code generation
2032
+ /// Sort the code generation.
2023
2033
sort_semantically : bool ,
2034
+
2035
+ /// Deduplicate `extern` blocks.
2036
+ deduplicate_extern_blocks : bool ,
2024
2037
}
2025
2038
2026
2039
/// TODO(emilio): This is sort of a lie (see the error message that results from
@@ -2170,6 +2183,7 @@ impl Default for BindgenOptions {
2170
2183
force_explicit_padding : false ,
2171
2184
vtable_generation : false ,
2172
2185
sort_semantically : false ,
2186
+ deduplicate_extern_blocks : false ,
2173
2187
}
2174
2188
}
2175
2189
}
@@ -2455,7 +2469,7 @@ impl Bindings {
2455
2469
2456
2470
let ( items, options, warnings) = codegen:: codegen ( context) ;
2457
2471
2458
- if options. sort_semantically {
2472
+ if options. sort_semantically || options . deduplicate_extern_blocks {
2459
2473
let module_wrapped_tokens =
2460
2474
quote ! ( mod wrapper_for_sorting_hack { #( #items ) * } ) ;
2461
2475
@@ -2475,26 +2489,81 @@ impl Bindings {
2475
2489
. unwrap ( )
2476
2490
. 1 ;
2477
2491
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
+ }
2498
2567
2499
2568
let synful_items = syn_parsed_items
2500
2569
. into_iter ( )
0 commit comments