summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs73
-rw-r--r--src/options.rs7
-rw-r--r--tests/expectations/tests/merge-extern-blocks.rs37
-rw-r--r--tests/headers/merge-extern-blocks.h6
4 files changed, 120 insertions, 3 deletions
diff --git a/src/lib.rs b/src/lib.rs
index c7fccb98..3c89368f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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());
@@ -1542,7 +1546,7 @@ 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 {
@@ -1550,6 +1554,12 @@ impl Builder {
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.
@@ -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
@@ -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) {
@@ -2258,6 +2271,7 @@ impl Default for BindgenOptions {
force_explicit_padding: false,
vtable_generation: false,
sort_semantically: false,
+ merge_extern_blocks: false,
}
}
}
@@ -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,
diff --git a/src/options.rs b/src/options.rs
index 1e87b6eb..f707ab9b 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -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"),
@@ -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))
}
diff --git a/tests/expectations/tests/merge-extern-blocks.rs b/tests/expectations/tests/merge-extern-blocks.rs
new file mode 100644
index 00000000..66ceeff0
--- /dev/null
+++ b/tests/expectations/tests/merge-extern-blocks.rs
@@ -0,0 +1,37 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Point {
+ pub x: ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_Point() {
+ const UNINIT: ::std::mem::MaybeUninit<Point> =
+ ::std::mem::MaybeUninit::uninit();
+ let ptr = UNINIT.as_ptr();
+ assert_eq!(
+ ::std::mem::size_of::<Point>(),
+ 4usize,
+ concat!("Size of: ", stringify!(Point))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Point>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(Point))
+ );
+ assert_eq!(
+ unsafe { ::std::ptr::addr_of!((*ptr).x) as usize - ptr as usize },
+ 0usize,
+ concat!("Offset of field: ", stringify!(Point), "::", stringify!(x))
+ );
+}
+extern "C" {
+ pub fn foo() -> ::std::os::raw::c_int;
+ pub fn bar() -> ::std::os::raw::c_int;
+}
diff --git a/tests/headers/merge-extern-blocks.h b/tests/headers/merge-extern-blocks.h
new file mode 100644
index 00000000..1d46b7d4
--- /dev/null
+++ b/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();