cbindgen/bindgen/
builder.rs

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
5use std::path;
6
7use crate::bindgen::bindings::Bindings;
8use crate::bindgen::cargo::Cargo;
9use crate::bindgen::config::{Braces, Config, Language, Profile, Style};
10use crate::bindgen::error::Error;
11use crate::bindgen::library::Library;
12use crate::bindgen::parser::{self, Parse};
13
14/// A builder for generating a bindings header.
15#[derive(Debug, Clone)]
16pub 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
25impl Builder {
26    #[allow(clippy::new_without_default)]
27    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)]
39    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)]
45    pub fn with_no_includes(mut self) -> Builder {
46        self.config.no_includes = true;
47        self
48    }
49
50    #[allow(unused)]
51    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)]
57    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)]
65    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)]
71    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)]
77    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)]
83    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)]
89    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)]
95    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)]
101    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)]
107    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)]
118    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)]
129    pub fn with_braces(mut self, braces: Braces) -> Builder {
130        self.config.braces = braces;
131        self
132    }
133
134    #[allow(unused)]
135    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)]
141    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)]
147    pub fn with_language(mut self, language: Language) -> Builder {
148        self.config.language = language;
149        self
150    }
151
152    #[allow(unused)]
153    pub fn with_cpp_compat(mut self, cpp_compat: bool) -> Builder {
154        self.config.cpp_compat = cpp_compat;
155        self
156    }
157
158    #[allow(unused)]
159    pub fn with_style(mut self, style: Style) -> Builder {
160        self.config.style = style;
161        self
162    }
163
164    #[allow(unused)]
165    pub fn include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
166        self.config
167            .export
168            .include
169            .push(String::from(item_name.as_ref()));
170        self
171    }
172
173    #[allow(unused)]
174    pub fn exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
175        self.config
176            .export
177            .exclude
178            .push(String::from(item_name.as_ref()));
179        self
180    }
181
182    #[allow(unused)]
183    pub fn rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder {
184        self.config
185            .export
186            .rename
187            .insert(String::from(from.as_ref()), String::from(to.as_ref()));
188        self
189    }
190
191    #[allow(unused)]
192    pub fn with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder {
193        self.config.export.prefix = Some(String::from(prefix.as_ref()));
194        self
195    }
196
197    #[allow(unused)]
198    pub fn with_parse_deps(mut self, parse_deps: bool) -> Builder {
199        self.config.parse.parse_deps = parse_deps;
200        self
201    }
202
203    #[allow(unused)]
204    pub fn with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder {
205        self.config.parse.include =
206            Some(include.iter().map(|x| String::from(x.as_ref())).collect());
207        self
208    }
209
210    #[allow(unused)]
211    pub fn with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder {
212        self.config.parse.exclude = exclude.iter().map(|x| String::from(x.as_ref())).collect();
213        self
214    }
215
216    #[allow(unused)]
217    pub fn with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder {
218        self.config.parse.expand.crates = expand.iter().map(|x| String::from(x.as_ref())).collect();
219        self
220    }
221
222    #[allow(unused)]
223    pub fn with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder {
224        self.config.parse.expand.all_features = expand_all_features;
225        self
226    }
227
228    #[allow(unused)]
229    pub fn with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder {
230        self.config.parse.expand.default_features = expand_default_features;
231        self
232    }
233
234    #[allow(unused)]
235    pub fn with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder {
236        self.config.parse.expand.features = Some(
237            expand_features
238                .iter()
239                .map(|x| String::from(x.as_ref()))
240                .collect(),
241        );
242        self
243    }
244
245    #[allow(unused)]
246    pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder {
247        self.config.parse.expand.profile = profile;
248        self
249    }
250
251    #[allow(unused)]
252    pub fn with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder {
253        self.config.parse.extra_bindings = extra_bindings
254            .iter()
255            .map(|x| String::from(x.as_ref()))
256            .collect();
257        self
258    }
259
260    #[allow(unused)]
261    pub fn with_only_target_dependencies(mut self, only_target_dependencies: bool) -> Builder {
262        self.config.only_target_dependencies = only_target_dependencies;
263        self
264    }
265
266    #[allow(unused)]
267    pub fn with_documentation(mut self, documentation: bool) -> Builder {
268        self.config.documentation = documentation;
269        self
270    }
271
272    #[allow(unused)]
273    pub fn with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder {
274        self.config.defines.insert(
275            format!("target_os = {}", platform),
276            preprocessor_define.to_owned(),
277        );
278        self
279    }
280
281    #[allow(unused)]
282    pub fn with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder {
283        self.config.defines.insert(
284            format!("{} = {}", key, value),
285            preprocessor_define.to_owned(),
286        );
287        self
288    }
289
290    #[allow(unused)]
291    pub fn with_config(mut self, config: Config) -> Builder {
292        self.config = config;
293        self
294    }
295
296    #[allow(unused)]
297    pub fn with_std_types(mut self, std_types: bool) -> Builder {
298        self.std_types = std_types;
299        self
300    }
301
302    #[allow(unused)]
303    pub fn with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder {
304        self.srcs.push(src.as_ref().to_owned());
305        self
306    }
307
308    #[allow(unused)]
309    pub fn with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder {
310        debug_assert!(self.lib.is_none());
311        debug_assert!(self.lib_cargo.is_none());
312        self.lib = Some((path::PathBuf::from(lib_dir.as_ref()), None));
313        self
314    }
315
316    #[allow(unused)]
317    pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>(
318        mut self,
319        lib_dir: P,
320        binding_lib_name: S,
321    ) -> Builder {
322        debug_assert!(self.lib.is_none());
323        debug_assert!(self.lib_cargo.is_none());
324        self.lib = Some((
325            path::PathBuf::from(lib_dir.as_ref()),
326            Some(String::from(binding_lib_name.as_ref())),
327        ));
328        self
329    }
330
331    #[allow(unused)]
332    pub(crate) fn with_cargo(mut self, lib: Cargo) -> Builder {
333        debug_assert!(self.lib.is_none());
334        debug_assert!(self.lib_cargo.is_none());
335        self.lib_cargo = Some(lib);
336        self
337    }
338
339    #[allow(unused)]
340    pub fn with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder {
341        debug_assert!(self.lockfile.is_none());
342        debug_assert!(self.lib_cargo.is_none());
343        self.lockfile = Some(path::PathBuf::from(lockfile.as_ref()));
344        self
345    }
346
347    pub fn generate(self) -> Result<Bindings, Error> {
348        // If macro expansion is enabled, then cbindgen will attempt to build the crate
349        // and will run its build script which may run cbindgen again. That second run may start
350        // infinite recursion, or overwrite previously written files with bindings.
351        // So if we are called recursively, we are skipping the whole generation
352        // and produce "noop" bindings that won't be able to overwrite anything.
353        if std::env::var("_CBINDGEN_IS_RUNNING").is_ok() {
354            return Ok(Bindings::new(
355                self.config,
356                Default::default(),
357                Default::default(),
358                Default::default(),
359                Default::default(),
360                Default::default(),
361                Default::default(),
362                Default::default(),
363                true,
364            ));
365        }
366
367        let mut result = Parse::new();
368
369        if self.std_types {
370            result.add_std_types();
371        }
372
373        for x in &self.srcs {
374            result.extend_with(&parser::parse_src(x, &self.config)?);
375        }
376
377        if let Some((lib_dir, binding_lib_name)) = self.lib.clone() {
378            let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str());
379
380            let cargo = Cargo::load(
381                &lib_dir,
382                lockfile,
383                binding_lib_name.as_deref(),
384                self.config.parse.parse_deps,
385                self.config.parse.clean,
386                self.config.only_target_dependencies,
387                /* existing_metadata = */ None,
388            )?;
389
390            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
391        } else if let Some(cargo) = self.lib_cargo.clone() {
392            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
393        }
394
395        result.source_files.extend_from_slice(self.srcs.as_slice());
396
397        Library::new(
398            self.config,
399            result.constants,
400            result.globals,
401            result.enums,
402            result.structs,
403            result.unions,
404            result.opaque_items,
405            result.typedefs,
406            result.functions,
407            result.source_files,
408        )
409        .generate()
410    }
411}
412
413#[cfg(test)]
414mod tests {
415    use super::*;
416
417    #[test]
418    fn with_style() {
419        assert_eq!(
420            Style::Tag,
421            Builder::new().with_style(Style::Tag).config.style
422        );
423    }
424}