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}
425