diff --git a/docs.md b/docs.md index 182684360..63ab3fe1a 100644 --- a/docs.md +++ b/docs.md @@ -751,6 +751,12 @@ exclude = ["libc"] # default: false clean = false +# Which crates other than the top-level binding crate we should generate +# bindings for. +# +# default: [] +extra_bindings = ["my_awesome_dep"] + [parse.expand] # A list of crate names that should be run through `cargo expand` before # parsing to expand any macros. Note that if a crate is named here, it diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index 22e437472..5d279c90d 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -322,25 +322,13 @@ impl Builder { result.extend_with(&parser::parse_lib( cargo, &self.config.macro_expansion, - self.config.parse.parse_deps, - &self.config.parse.include, - &self.config.parse.exclude, - &self.config.parse.expand.crates, - self.config.parse.expand.all_features, - self.config.parse.expand.default_features, - &self.config.parse.expand.features, + &self.config.parse, )?); } else if let Some(cargo) = self.lib_cargo.clone() { result.extend_with(&parser::parse_lib( cargo, &self.config.macro_expansion, - self.config.parse.parse_deps, - &self.config.parse.include, - &self.config.parse.exclude, - &self.config.parse.expand.crates, - self.config.parse.expand.all_features, - self.config.parse.expand.default_features, - &self.config.parse.expand.features, + &self.config.parse, )?); } diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 2192e6e16..d2b13d71b 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -538,7 +538,7 @@ fn retrocomp_parse_expand_config_deserialize<'de, D: Deserializer<'de>>( } /// Settings to apply when parsing. -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Default, Clone, Deserialize)] #[serde(rename_all = "snake_case")] #[serde(deny_unknown_fields)] #[serde(default)] @@ -562,17 +562,23 @@ pub struct ParseConfig { /// Whether to use a new temporary target directory when running `rustc --pretty=expanded`. /// This may be required for some build processes. pub clean: bool, + /// List of crate names which generate consts, statics, and fns. By default + /// no dependent crates generate them. + pub extra_bindings: Vec, } -impl Default for ParseConfig { - fn default() -> ParseConfig { - ParseConfig { - parse_deps: false, - include: None, - exclude: Vec::new(), - expand: ParseExpandConfig::default(), - clean: false, +impl ParseConfig { + pub(crate) fn should_generate_top_level_item( + &self, + crate_name: &str, + binding_crate_name: &str, + ) -> bool { + if crate_name == binding_crate_name { + // Always generate items for the binding crate. + return true; } + + self.extra_bindings.iter().any(|dep| dep == crate_name) } } diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index 190f6bd59..a7cd618fd 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -11,7 +11,7 @@ use syn; use bindgen::bitflags; use bindgen::cargo::{Cargo, PackageRef}; -use bindgen::config::MacroExpansionConfig; +use bindgen::config::{MacroExpansionConfig, ParseConfig}; use bindgen::error::Error; use bindgen::ir::{ AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParams, ItemMap, @@ -36,18 +36,16 @@ pub fn parse_src( macro_expansion_config: &MacroExpansionConfig, ) -> ParseResult { let mod_name = src_file.file_stem().unwrap().to_str().unwrap(); + let parse_config = ParseConfig { + parse_deps: true, + ..ParseConfig::default() + }; let mut context = Parser { binding_crate_name: mod_name.to_owned(), macro_expansion_config, + parse_config: &parse_config, lib: None, - parse_deps: true, - include: None, - exclude: Vec::new(), - expand: Vec::new(), - expand_all_features: true, - expand_default_features: true, - expand_features: None, parsed_crates: HashSet::new(), cache_src: HashMap::new(), cache_expanded_crate: HashMap::new(), @@ -72,25 +70,13 @@ pub fn parse_src( pub(crate) fn parse_lib( lib: Cargo, macro_expansion_config: &MacroExpansionConfig, - parse_deps: bool, - include: &Option>, - exclude: &[String], - expand: &[String], - expand_all_features: bool, - expand_default_features: bool, - expand_features: &Option>, + parse_config: &ParseConfig, ) -> ParseResult { let mut context = Parser { binding_crate_name: lib.binding_crate_name().to_owned(), macro_expansion_config, + parse_config, lib: Some(lib), - parse_deps: parse_deps, - include: include.clone(), - exclude: exclude.to_owned(), - expand: expand.to_owned(), - expand_all_features, - expand_default_features, - expand_features: expand_features.clone(), parsed_crates: HashSet::new(), cache_src: HashMap::new(), cache_expanded_crate: HashMap::new(), @@ -106,16 +92,9 @@ pub(crate) fn parse_lib( #[derive(Debug, Clone)] struct Parser<'a> { binding_crate_name: String, - macro_expansion_config: &'a MacroExpansionConfig, lib: Option, - parse_deps: bool, - - include: Option>, - exclude: Vec, - expand: Vec, - expand_all_features: bool, - expand_default_features: bool, - expand_features: Option>, + macro_expansion_config: &'a MacroExpansionConfig, + parse_config: &'a ParseConfig, parsed_crates: HashSet, cache_src: HashMap>, @@ -132,24 +111,25 @@ impl<'a> Parser<'a> { return false; } - if !self.parse_deps { + if !self.parse_config.parse_deps { return false; } // Skip any whitelist or blacklist for expand - if self.expand.contains(&pkg_name) { + if self.parse_config.expand.crates.contains(&pkg_name) { return true; } // If we have a whitelist, check it - if let Some(ref include) = self.include { + if let Some(ref include) = self.parse_config.include { if !include.contains(&pkg_name) { return false; } } // Check the blacklist - return !STD_CRATES.contains(&pkg_name.as_ref()) && !self.exclude.contains(&pkg_name); + return !STD_CRATES.contains(&pkg_name.as_ref()) + && !self.parse_config.exclude.contains(&pkg_name); } fn parse_crate(&mut self, pkg: &PackageRef) -> Result<(), Error> { @@ -157,7 +137,7 @@ impl<'a> Parser<'a> { self.parsed_crates.insert(pkg.name.clone()); // Check if we should use cargo expand for this crate - if self.expand.contains(&pkg.name) { + if self.parse_config.expand.crates.contains(&pkg.name) { return self.parse_expand_crate(pkg); } @@ -207,9 +187,9 @@ impl<'a> Parser<'a> { .unwrap() .expand_crate( pkg, - self.expand_all_features, - self.expand_default_features, - &self.expand_features, + self.parse_config.expand.all_features, + self.parse_config.expand.default_features, + &self.parse_config.expand.features, ) .map_err(|x| Error::CargoExpand(pkg.name.clone(), x))?; let i = syn::parse_file(&s).map_err(|x| Error::ParseSyntaxError { @@ -229,6 +209,7 @@ impl<'a> Parser<'a> { fn process_expanded_mod(&mut self, pkg: &PackageRef, items: &[syn::Item]) -> Result<(), Error> { self.out.load_syn_crate_mod( &self.macro_expansion_config, + &self.parse_config, &self.binding_crate_name, &pkg.name, Cfg::join(&self.cfg_stack).as_ref(), @@ -304,6 +285,7 @@ impl<'a> Parser<'a> { ) -> Result<(), Error> { self.out.load_syn_crate_mod( &self.macro_expansion_config, + &self.parse_config, &self.binding_crate_name, &pkg.name, Cfg::join(&self.cfg_stack).as_ref(), @@ -446,6 +428,7 @@ impl Parse { pub fn load_syn_crate_mod( &mut self, macro_expansion_config: &MacroExpansionConfig, + parse_config: &ParseConfig, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, @@ -459,16 +442,34 @@ impl Parse { } match item { syn::Item::ForeignMod(ref item) => { - self.load_syn_foreign_mod(binding_crate_name, crate_name, mod_cfg, item); + self.load_syn_foreign_mod( + parse_config, + binding_crate_name, + crate_name, + mod_cfg, + item, + ); } syn::Item::Fn(ref item) => { - self.load_syn_fn(binding_crate_name, crate_name, mod_cfg, item); + self.load_syn_fn(parse_config, binding_crate_name, crate_name, mod_cfg, item); } syn::Item::Const(ref item) => { - self.load_syn_const(binding_crate_name, crate_name, mod_cfg, item); + self.load_syn_const( + parse_config, + binding_crate_name, + crate_name, + mod_cfg, + item, + ); } syn::Item::Static(ref item) => { - self.load_syn_static(binding_crate_name, crate_name, mod_cfg, item); + self.load_syn_static( + parse_config, + binding_crate_name, + crate_name, + mod_cfg, + item, + ); } syn::Item::Struct(ref item) => { self.load_syn_struct(crate_name, mod_cfg, item); @@ -524,6 +525,7 @@ impl Parse { /// Enters a `extern "C" { }` declaration and loads function declarations. fn load_syn_foreign_mod( &mut self, + parse_config: &ParseConfig, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, @@ -537,7 +539,8 @@ impl Parse { for foreign_item in &item.items { match *foreign_item { syn::ForeignItem::Fn(ref function) => { - if crate_name != binding_crate_name { + if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) + { info!( "Skip {}::{} - (fn's outside of the binding crate are not used).", crate_name, &function.ident @@ -567,12 +570,13 @@ impl Parse { /// Loads a `fn` declaration fn load_syn_fn( &mut self, + parse_config: &ParseConfig, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemFn, ) { - if crate_name != binding_crate_name { + if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) { info!( "Skip {}::{} - (fn's outside of the binding crate are not used).", crate_name, &item.ident @@ -681,12 +685,13 @@ impl Parse { /// Loads a `const` declaration fn load_syn_const( &mut self, + parse_config: &ParseConfig, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemConst, ) { - if crate_name != binding_crate_name { + if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) { info!( "Skip {}::{} - (const's outside of the binding crate are not used).", crate_name, &item.ident @@ -719,12 +724,13 @@ impl Parse { /// Loads a `static` declaration fn load_syn_static( &mut self, + parse_config: &ParseConfig, binding_crate_name: &str, crate_name: &str, mod_cfg: Option<&Cfg>, item: &syn::ItemStatic, ) { - if crate_name != binding_crate_name { + if !parse_config.should_generate_top_level_item(crate_name, binding_crate_name) { info!( "Skip {}::{} - (static's outside of the binding crate are not used).", crate_name, &item.ident diff --git a/template.toml b/template.toml index 1bb4a92b4..d61e5c25b 100644 --- a/template.toml +++ b/template.toml @@ -127,6 +127,7 @@ parse_deps = false # include = [] exclude = [] clean = false +extra_bindings = [] diff --git a/tests/expectations/both/workspace.c b/tests/expectations/both/workspace.c index cb37ff688..d048da989 100644 --- a/tests/expectations/both/workspace.c +++ b/tests/expectations/both/workspace.c @@ -3,6 +3,8 @@ #include #include +#define EXT_CONST 0 + typedef struct ExtType { uint32_t data; } ExtType; diff --git a/tests/expectations/both/workspace.compat.c b/tests/expectations/both/workspace.compat.c index d0d8d3be5..3e5182f99 100644 --- a/tests/expectations/both/workspace.compat.c +++ b/tests/expectations/both/workspace.compat.c @@ -3,6 +3,8 @@ #include #include +#define EXT_CONST 0 + typedef struct ExtType { uint32_t data; } ExtType; diff --git a/tests/expectations/tag/workspace.c b/tests/expectations/tag/workspace.c index ad7ad56ab..4c16fcdae 100644 --- a/tests/expectations/tag/workspace.c +++ b/tests/expectations/tag/workspace.c @@ -3,6 +3,8 @@ #include #include +#define EXT_CONST 0 + struct ExtType { uint32_t data; }; diff --git a/tests/expectations/tag/workspace.compat.c b/tests/expectations/tag/workspace.compat.c index 1591a0ada..8e4596fdf 100644 --- a/tests/expectations/tag/workspace.compat.c +++ b/tests/expectations/tag/workspace.compat.c @@ -3,6 +3,8 @@ #include #include +#define EXT_CONST 0 + struct ExtType { uint32_t data; }; diff --git a/tests/expectations/workspace.c b/tests/expectations/workspace.c index 04b65dc2b..200813d2a 100644 --- a/tests/expectations/workspace.c +++ b/tests/expectations/workspace.c @@ -3,6 +3,8 @@ #include #include +#define EXT_CONST 0 + typedef struct { uint32_t data; } ExtType; diff --git a/tests/expectations/workspace.compat.c b/tests/expectations/workspace.compat.c index 1529006ba..dd8b86c89 100644 --- a/tests/expectations/workspace.compat.c +++ b/tests/expectations/workspace.compat.c @@ -3,6 +3,8 @@ #include #include +#define EXT_CONST 0 + typedef struct { uint32_t data; } ExtType; diff --git a/tests/expectations/workspace.cpp b/tests/expectations/workspace.cpp index 617a4eb0d..8820d3414 100644 --- a/tests/expectations/workspace.cpp +++ b/tests/expectations/workspace.cpp @@ -3,6 +3,8 @@ #include #include +static const int32_t EXT_CONST = 0; + struct ExtType { uint32_t data; }; diff --git a/tests/rust/workspace/cbindgen.toml b/tests/rust/workspace/cbindgen.toml index 3bfcd8c19..d2fea7e78 100644 --- a/tests/rust/workspace/cbindgen.toml +++ b/tests/rust/workspace/cbindgen.toml @@ -1,2 +1,3 @@ [parse] parse_deps = true +extra_bindings = ["dep"] diff --git a/tests/rust/workspace/dep/src/lib.rs b/tests/rust/workspace/dep/src/lib.rs index b9ee4ab81..37337c441 100644 --- a/tests/rust/workspace/dep/src/lib.rs +++ b/tests/rust/workspace/dep/src/lib.rs @@ -2,3 +2,5 @@ pub struct ExtType { pub data: u32, } + +pub const EXT_CONST: i32 = 0;