diff --git a/docs.md b/docs.md index c8ce9f4f2..465313c3e 100644 --- a/docs.md +++ b/docs.md @@ -596,6 +596,11 @@ include = ["MyOrphanStruct", "MyGreatTypeRename"] # default: [] exclude = ["Bad"] +# A list of items to include in the generated bindings, while excluding other unlisted +# items from being exported. Has lower precedence than `include` and `exclude`, so they +# can still add or remove items regardless of the whitelist's value. +whitelist = ["MyImportantStruct", "Bad"] + # A prefix to add before the name of every item # default: no prefix is added prefix = "CAPI_" diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 31316503d..72f382153 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -327,6 +327,11 @@ pub struct ExportConfig { pub include: Vec, /// A list of items to not include in the generated bindings pub exclude: Vec, + /// A list of whitelisted items. When non-empty, only items included in the + /// whitelist will be included in the generated bindings. `include` and + /// `exclude` have priority over this, and will add or remove items to/from + /// the generated bindings regardless of their inclusion in the whitelist. + pub whitelist: Vec, /// Table of name conversions to apply to item names pub rename: HashMap, /// Table of raw strings to prepend to the body of items. diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f9..4e3cb3063 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -72,6 +72,9 @@ impl Library { if self.config.language != Language::Cxx { self.instantiate_monomorphs(); } + if !self.config.export.whitelist.is_empty() { + self.remove_non_whitelisted(); + } self.remove_excluded(); if self.config.language == Language::C { self.resolve_declaration_types(); @@ -90,7 +93,14 @@ impl Library { self.constants.for_all_items(|constant| { constant.add_dependencies(&self, &mut dependencies); }); - for name in &self.config.export.include { + + let inclusions = self + .config + .export + .include + .iter() + .chain(self.config.export.whitelist.iter()); + for name in inclusions { let path = Path::new(name.clone()); if let Some(items) = self.get_items(&path) { if dependencies.items.insert(path) { @@ -172,6 +182,32 @@ impl Library { &self.config } + fn remove_non_whitelisted(&mut self) { + let whitelist = self + .config + .export + .whitelist + .iter() + .chain(self.config.export.include.iter()); + + self.functions + .retain(|x| whitelist.clone().any(|y| y == x.path().name())); + self.enums + .filter(|x| !whitelist.clone().any(|y| y == x.path().name())); + self.structs + .filter(|x| !whitelist.clone().any(|y| y == x.path().name())); + self.unions + .filter(|x| !whitelist.clone().any(|y| y == x.path().name())); + self.opaque_items + .filter(|x| !whitelist.clone().any(|y| y == x.path().name())); + self.typedefs + .filter(|x| !whitelist.clone().any(|y| y == x.path().name())); + self.globals + .filter(|x| !whitelist.clone().any(|y| y == x.path().name())); + self.constants + .filter(|x| !whitelist.clone().any(|y| y == x.path().name())); + } + fn remove_excluded(&mut self) { let config = &self.config; // FIXME: interpret `config.export.exclude` as `Path`s.