1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use std::path; 6 7 use crate::bindgen::bindings::Bindings; 8 use crate::bindgen::cargo::Cargo; 9 use crate::bindgen::config::{Braces, Config, Language, Profile, Style}; 10 use crate::bindgen::error::Error; 11 use crate::bindgen::library::Library; 12 use crate::bindgen::parser::{self, Parse}; 13 14 /// A builder for generating a bindings header. 15 #[derive(Debug, Clone)] 16 pub struct Builder { 17 config: Config, 18 srcs: Vec<path::PathBuf>, 19 lib: Option<(path::PathBuf, Option<String>)>, 20 lib_cargo: Option<Cargo>, 21 std_types: bool, 22 lockfile: Option<path::PathBuf>, 23 } 24 25 impl Builder { 26 #[allow(clippy::new_without_default)] new() -> Builder27 pub fn new() -> Builder { 28 Builder { 29 config: Config::default(), 30 srcs: Vec::new(), 31 lib: None, 32 lib_cargo: None, 33 std_types: true, 34 lockfile: None, 35 } 36 } 37 38 #[allow(unused)] with_header<S: AsRef<str>>(mut self, header: S) -> Builder39 pub fn with_header<S: AsRef<str>>(mut self, header: S) -> Builder { 40 self.config.header = Some(String::from(header.as_ref())); 41 self 42 } 43 44 #[allow(unused)] with_no_includes(mut self) -> Builder45 pub fn with_no_includes(mut self) -> Builder { 46 self.config.no_includes = true; 47 self 48 } 49 50 #[allow(unused)] with_include<S: AsRef<str>>(mut self, include: S) -> Builder51 pub fn with_include<S: AsRef<str>>(mut self, include: S) -> Builder { 52 self.config.includes.push(String::from(include.as_ref())); 53 self 54 } 55 56 #[allow(unused)] with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder57 pub fn with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder { 58 self.config 59 .sys_includes 60 .push(String::from(include.as_ref())); 61 self 62 } 63 64 #[allow(unused)] with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder65 pub fn with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder { 66 self.config.after_includes = Some(String::from(line.as_ref())); 67 self 68 } 69 70 #[allow(unused)] with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder71 pub fn with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder { 72 self.config.trailer = Some(String::from(trailer.as_ref())); 73 self 74 } 75 76 #[allow(unused)] with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder77 pub fn with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder { 78 self.config.include_guard = Some(String::from(include_guard.as_ref())); 79 self 80 } 81 82 #[allow(unused)] with_pragma_once(mut self, pragma_once: bool) -> Builder83 pub fn with_pragma_once(mut self, pragma_once: bool) -> Builder { 84 self.config.pragma_once = pragma_once; 85 self 86 } 87 88 #[allow(unused)] with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder89 pub fn with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder { 90 self.config.autogen_warning = Some(String::from(autogen_warning.as_ref())); 91 self 92 } 93 94 #[allow(unused)] with_include_version(mut self, include_version: bool) -> Builder95 pub fn with_include_version(mut self, include_version: bool) -> Builder { 96 self.config.include_version = include_version; 97 self 98 } 99 100 #[allow(unused)] with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder101 pub fn with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder { 102 self.config.namespace = Some(String::from(namespace.as_ref())); 103 self 104 } 105 106 #[allow(unused)] with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder107 pub fn with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder { 108 self.config.namespaces = Some( 109 namespaces 110 .iter() 111 .map(|x| String::from(x.as_ref())) 112 .collect(), 113 ); 114 self 115 } 116 117 #[allow(unused)] with_using_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder118 pub fn with_using_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder { 119 self.config.using_namespaces = Some( 120 namespaces 121 .iter() 122 .map(|x| String::from(x.as_ref())) 123 .collect(), 124 ); 125 self 126 } 127 128 #[allow(unused)] with_braces(mut self, braces: Braces) -> Builder129 pub fn with_braces(mut self, braces: Braces) -> Builder { 130 self.config.braces = braces; 131 self 132 } 133 134 #[allow(unused)] with_line_length(mut self, line_length: usize) -> Builder135 pub fn with_line_length(mut self, line_length: usize) -> Builder { 136 self.config.line_length = line_length; 137 self 138 } 139 140 #[allow(unused)] with_tab_width(mut self, tab_width: usize) -> Builder141 pub fn with_tab_width(mut self, tab_width: usize) -> Builder { 142 self.config.tab_width = tab_width; 143 self 144 } 145 146 #[allow(unused)] with_language(mut self, language: Language) -> Builder147 pub fn with_language(mut self, language: Language) -> Builder { 148 self.config.language = language; 149 self 150 } 151 152 #[allow(unused)] with_style(mut self, style: Style) -> Builder153 pub fn with_style(mut self, style: Style) -> Builder { 154 self.config.style = style; 155 self 156 } 157 158 #[allow(unused)] include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder159 pub fn include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder { 160 self.config 161 .export 162 .include 163 .push(String::from(item_name.as_ref())); 164 self 165 } 166 167 #[allow(unused)] exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder168 pub fn exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder { 169 self.config 170 .export 171 .exclude 172 .push(String::from(item_name.as_ref())); 173 self 174 } 175 176 #[allow(unused)] rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder177 pub fn rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder { 178 self.config 179 .export 180 .rename 181 .insert(String::from(from.as_ref()), String::from(to.as_ref())); 182 self 183 } 184 185 #[allow(unused)] with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder186 pub fn with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder { 187 self.config.export.prefix = Some(String::from(prefix.as_ref())); 188 self 189 } 190 191 #[allow(unused)] with_parse_deps(mut self, parse_deps: bool) -> Builder192 pub fn with_parse_deps(mut self, parse_deps: bool) -> Builder { 193 self.config.parse.parse_deps = parse_deps; 194 self 195 } 196 197 #[allow(unused)] with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder198 pub fn with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder { 199 self.config.parse.include = 200 Some(include.iter().map(|x| String::from(x.as_ref())).collect()); 201 self 202 } 203 204 #[allow(unused)] with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder205 pub fn with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder { 206 self.config.parse.exclude = exclude.iter().map(|x| String::from(x.as_ref())).collect(); 207 self 208 } 209 210 #[allow(unused)] with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder211 pub fn with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder { 212 self.config.parse.expand.crates = expand.iter().map(|x| String::from(x.as_ref())).collect(); 213 self 214 } 215 216 #[allow(unused)] with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder217 pub fn with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder { 218 self.config.parse.expand.all_features = expand_all_features; 219 self 220 } 221 222 #[allow(unused)] with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder223 pub fn with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder { 224 self.config.parse.expand.default_features = expand_default_features; 225 self 226 } 227 228 #[allow(unused)] with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder229 pub fn with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder { 230 self.config.parse.expand.features = Some( 231 expand_features 232 .iter() 233 .map(|x| String::from(x.as_ref())) 234 .collect(), 235 ); 236 self 237 } 238 239 #[allow(unused)] with_parse_expand_profile(mut self, profile: Profile) -> Builder240 pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder { 241 self.config.parse.expand.profile = profile; 242 self 243 } 244 245 #[allow(unused)] with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder246 pub fn with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder { 247 self.config.parse.extra_bindings = extra_bindings 248 .iter() 249 .map(|x| String::from(x.as_ref())) 250 .collect(); 251 self 252 } 253 254 #[allow(unused)] with_only_target_dependencies(mut self, only_target_dependencies: bool) -> Builder255 pub fn with_only_target_dependencies(mut self, only_target_dependencies: bool) -> Builder { 256 self.config.only_target_dependencies = only_target_dependencies; 257 self 258 } 259 260 #[allow(unused)] with_documentation(mut self, documentation: bool) -> Builder261 pub fn with_documentation(mut self, documentation: bool) -> Builder { 262 self.config.documentation = documentation; 263 self 264 } 265 266 #[allow(unused)] with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder267 pub fn with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder { 268 self.config.defines.insert( 269 format!("target_os = {}", platform), 270 preprocessor_define.to_owned(), 271 ); 272 self 273 } 274 275 #[allow(unused)] with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder276 pub fn with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder { 277 self.config.defines.insert( 278 format!("{} = {}", key, value), 279 preprocessor_define.to_owned(), 280 ); 281 self 282 } 283 284 #[allow(unused)] with_config(mut self, config: Config) -> Builder285 pub fn with_config(mut self, config: Config) -> Builder { 286 self.config = config; 287 self 288 } 289 290 #[allow(unused)] with_std_types(mut self, std_types: bool) -> Builder291 pub fn with_std_types(mut self, std_types: bool) -> Builder { 292 self.std_types = std_types; 293 self 294 } 295 296 #[allow(unused)] with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder297 pub fn with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder { 298 self.srcs.push(src.as_ref().to_owned()); 299 self 300 } 301 302 #[allow(unused)] with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder303 pub fn with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder { 304 debug_assert!(self.lib.is_none()); 305 debug_assert!(self.lib_cargo.is_none()); 306 self.lib = Some((path::PathBuf::from(lib_dir.as_ref()), None)); 307 self 308 } 309 310 #[allow(unused)] with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>( mut self, lib_dir: P, binding_lib_name: S, ) -> Builder311 pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>( 312 mut self, 313 lib_dir: P, 314 binding_lib_name: S, 315 ) -> Builder { 316 debug_assert!(self.lib.is_none()); 317 debug_assert!(self.lib_cargo.is_none()); 318 self.lib = Some(( 319 path::PathBuf::from(lib_dir.as_ref()), 320 Some(String::from(binding_lib_name.as_ref())), 321 )); 322 self 323 } 324 325 #[allow(unused)] with_cargo(mut self, lib: Cargo) -> Builder326 pub(crate) fn with_cargo(mut self, lib: Cargo) -> Builder { 327 debug_assert!(self.lib.is_none()); 328 debug_assert!(self.lib_cargo.is_none()); 329 self.lib_cargo = Some(lib); 330 self 331 } 332 333 #[allow(unused)] with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder334 pub fn with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder { 335 debug_assert!(self.lockfile.is_none()); 336 debug_assert!(self.lib_cargo.is_none()); 337 self.lockfile = Some(path::PathBuf::from(lockfile.as_ref())); 338 self 339 } 340 generate(self) -> Result<Bindings, Error>341 pub fn generate(self) -> Result<Bindings, Error> { 342 let mut result = Parse::new(); 343 344 if self.std_types { 345 result.add_std_types(); 346 } 347 348 for x in &self.srcs { 349 result.extend_with(&parser::parse_src(x, &self.config)?); 350 } 351 352 if let Some((lib_dir, binding_lib_name)) = self.lib.clone() { 353 let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str()); 354 355 let cargo = Cargo::load( 356 &lib_dir, 357 lockfile, 358 binding_lib_name.as_deref(), 359 self.config.parse.parse_deps, 360 self.config.parse.clean, 361 self.config.only_target_dependencies, 362 /* existing_metadata = */ None, 363 )?; 364 365 result.extend_with(&parser::parse_lib(cargo, &self.config)?); 366 } else if let Some(cargo) = self.lib_cargo.clone() { 367 result.extend_with(&parser::parse_lib(cargo, &self.config)?); 368 } 369 370 Library::new( 371 self.config, 372 result.constants, 373 result.globals, 374 result.enums, 375 result.structs, 376 result.unions, 377 result.opaque_items, 378 result.typedefs, 379 result.functions, 380 ) 381 .generate() 382 } 383 } 384 385 #[cfg(test)] 386 mod tests { 387 use super::*; 388 389 #[test] with_style()390 fn with_style() { 391 assert_eq!( 392 Style::Tag, 393 Builder::new().with_style(Style::Tag).config.style 394 ); 395 } 396 } 397