1 | //! Generate Rust bindings for C and C++ libraries. |
2 | //! |
3 | //! Provide a C/C++ header file, receive Rust FFI code to call into C/C++ |
4 | //! functions and use types defined in the header. |
5 | //! |
6 | //! See the [`Builder`](./struct.Builder.html) struct for usage. |
7 | //! |
8 | //! See the [Users Guide](https://rust-lang.github.io/rust-bindgen/) for |
9 | //! additional documentation. |
10 | #![deny (missing_docs)] |
11 | #![deny (unused_extern_crates)] |
12 | // To avoid rather annoying warnings when matching with CXCursor_xxx as a |
13 | // constant. |
14 | #![allow (non_upper_case_globals)] |
15 | // `quote!` nests quite deeply. |
16 | #![recursion_limit = "128" ] |
17 | |
18 | #[macro_use ] |
19 | extern crate bitflags; |
20 | #[macro_use ] |
21 | extern crate lazy_static; |
22 | #[macro_use ] |
23 | extern crate quote; |
24 | |
25 | #[cfg (feature = "logging" )] |
26 | #[macro_use ] |
27 | extern crate log; |
28 | |
29 | #[cfg (not(feature = "logging" ))] |
30 | #[macro_use ] |
31 | mod log_stubs; |
32 | |
33 | #[macro_use ] |
34 | mod extra_assertions; |
35 | |
36 | // A macro to declare an internal module for which we *must* provide |
37 | // documentation for. If we are building with the "testing_only_docs" feature, |
38 | // then the module is declared public, and our `#![deny(missing_docs)]` pragma |
39 | // applies to it. This feature is used in CI, so we won't let anything slip by |
40 | // undocumented. Normal builds, however, will leave the module private, so that |
41 | // we don't expose internals to library consumers. |
42 | macro_rules! doc_mod { |
43 | ($m:ident, $doc_mod_name:ident) => { |
44 | #[cfg(feature = "testing_only_docs" )] |
45 | pub mod $doc_mod_name { |
46 | //! Autogenerated documentation module. |
47 | pub use super::$m::*; |
48 | } |
49 | }; |
50 | } |
51 | |
52 | macro_rules! fn_with_regex_arg { |
53 | ($(#[$attrs:meta])* pub fn $($tokens:tt)*) => { |
54 | $(#[$attrs])* |
55 | /// Check the [regular expression arguments] section and the [regex] crate |
56 | /// documentation for further information. |
57 | /// |
58 | /// [regular expression arguments]: ./struct.Builder.html#regular-expression-arguments |
59 | /// [regex]: <https://docs.rs/regex> |
60 | pub fn $($tokens)* |
61 | }; |
62 | } |
63 | |
64 | mod clang; |
65 | mod codegen; |
66 | mod deps; |
67 | mod features; |
68 | pub mod ir; |
69 | mod parse; |
70 | mod regex_set; |
71 | mod time; |
72 | |
73 | pub mod callbacks; |
74 | |
75 | doc_mod!(clang, clang_docs); |
76 | doc_mod!(features, features_docs); |
77 | doc_mod!(ir, ir_docs); |
78 | doc_mod!(parse, parse_docs); |
79 | doc_mod!(regex_set, regex_set_docs); |
80 | |
81 | use codegen::CodegenError; |
82 | use ir::comment; |
83 | |
84 | pub use crate::codegen::{ |
85 | AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle, |
86 | }; |
87 | use crate::features::RustFeatures; |
88 | pub use crate::features::{ |
89 | RustTarget, LATEST_STABLE_RUST, RUST_TARGET_STRINGS, |
90 | }; |
91 | use crate::ir::context::{BindgenContext, ItemId}; |
92 | pub use crate::ir::function::Abi; |
93 | use crate::ir::item::Item; |
94 | use crate::parse::ParseError; |
95 | pub use crate::regex_set::RegexSet; |
96 | |
97 | use std::borrow::Cow; |
98 | use std::env; |
99 | use std::fs::{File, OpenOptions}; |
100 | use std::io::{self, Write}; |
101 | use std::path::{Path, PathBuf}; |
102 | use std::process::{Command, Stdio}; |
103 | use std::rc::Rc; |
104 | |
105 | // Some convenient typedefs for a fast hash map and hash set. |
106 | type HashMap<K, V> = ::rustc_hash::FxHashMap<K, V>; |
107 | type HashSet<K> = ::rustc_hash::FxHashSet<K>; |
108 | pub(crate) use std::collections::hash_map::Entry; |
109 | |
110 | /// Default prefix for the anon fields. |
111 | pub const DEFAULT_ANON_FIELDS_PREFIX: &str = "__bindgen_anon_" ; |
112 | const DEFAULT_NON_EXTERN_FNS_SUFFIX: &str = "__extern" ; |
113 | |
114 | fn file_is_cpp(name_file: &str) -> bool { |
115 | name_file.ends_with(".hpp" ) || |
116 | name_file.ends_with(".hxx" ) || |
117 | name_file.ends_with(".hh" ) || |
118 | name_file.ends_with(".h++" ) |
119 | } |
120 | |
121 | fn args_are_cpp(clang_args: &[String]) -> bool { |
122 | for w: &[String] in clang_args.windows(size:2) { |
123 | if w[0] == "-xc++" || w[1] == "-xc++" { |
124 | return true; |
125 | } |
126 | if w[0] == "-x" && w[1] == "c++" { |
127 | return true; |
128 | } |
129 | if w[0] == "-include" && file_is_cpp(&w[1]) { |
130 | return true; |
131 | } |
132 | } |
133 | false |
134 | } |
135 | |
136 | bitflags! { |
137 | /// A type used to indicate which kind of items we have to generate. |
138 | pub struct CodegenConfig: u32 { |
139 | /// Whether to generate functions. |
140 | const FUNCTIONS = 1 << 0; |
141 | /// Whether to generate types. |
142 | const TYPES = 1 << 1; |
143 | /// Whether to generate constants. |
144 | const VARS = 1 << 2; |
145 | /// Whether to generate methods. |
146 | const METHODS = 1 << 3; |
147 | /// Whether to generate constructors |
148 | const CONSTRUCTORS = 1 << 4; |
149 | /// Whether to generate destructors. |
150 | const DESTRUCTORS = 1 << 5; |
151 | } |
152 | } |
153 | |
154 | impl CodegenConfig { |
155 | /// Returns true if functions should be generated. |
156 | pub fn functions(self) -> bool { |
157 | self.contains(CodegenConfig::FUNCTIONS) |
158 | } |
159 | |
160 | /// Returns true if types should be generated. |
161 | pub fn types(self) -> bool { |
162 | self.contains(CodegenConfig::TYPES) |
163 | } |
164 | |
165 | /// Returns true if constants should be generated. |
166 | pub fn vars(self) -> bool { |
167 | self.contains(CodegenConfig::VARS) |
168 | } |
169 | |
170 | /// Returns true if methds should be generated. |
171 | pub fn methods(self) -> bool { |
172 | self.contains(CodegenConfig::METHODS) |
173 | } |
174 | |
175 | /// Returns true if constructors should be generated. |
176 | pub fn constructors(self) -> bool { |
177 | self.contains(CodegenConfig::CONSTRUCTORS) |
178 | } |
179 | |
180 | /// Returns true if destructors should be generated. |
181 | pub fn destructors(self) -> bool { |
182 | self.contains(CodegenConfig::DESTRUCTORS) |
183 | } |
184 | } |
185 | |
186 | impl Default for CodegenConfig { |
187 | fn default() -> Self { |
188 | CodegenConfig::all() |
189 | } |
190 | } |
191 | |
192 | /// Configure and generate Rust bindings for a C/C++ header. |
193 | /// |
194 | /// This is the main entry point to the library. |
195 | /// |
196 | /// ```ignore |
197 | /// use bindgen::builder; |
198 | /// |
199 | /// // Configure and generate bindings. |
200 | /// let bindings = builder().header("path/to/input/header" ) |
201 | /// .allowlist_type("SomeCoolClass" ) |
202 | /// .allowlist_function("do_some_cool_thing" ) |
203 | /// .generate()?; |
204 | /// |
205 | /// // Write the generated bindings to an output file. |
206 | /// bindings.write_to_file("path/to/output.rs" )?; |
207 | /// ``` |
208 | /// |
209 | /// # Enums |
210 | /// |
211 | /// Bindgen can map C/C++ enums into Rust in different ways. The way bindgen maps enums depends on |
212 | /// the pattern passed to several methods: |
213 | /// |
214 | /// 1. [`constified_enum_module()`](#method.constified_enum_module) |
215 | /// 2. [`bitfield_enum()`](#method.bitfield_enum) |
216 | /// 3. [`newtype_enum()`](#method.newtype_enum) |
217 | /// 4. [`rustified_enum()`](#method.rustified_enum) |
218 | /// |
219 | /// For each C enum, bindgen tries to match the pattern in the following order: |
220 | /// |
221 | /// 1. Constified enum module |
222 | /// 2. Bitfield enum |
223 | /// 3. Newtype enum |
224 | /// 4. Rustified enum |
225 | /// |
226 | /// If none of the above patterns match, then bindgen will generate a set of Rust constants. |
227 | /// |
228 | /// # Clang arguments |
229 | /// |
230 | /// Extra arguments can be passed to with clang: |
231 | /// 1. [`clang_arg()`](#method.clang_arg): takes a single argument |
232 | /// 2. [`clang_args()`](#method.clang_args): takes an iterator of arguments |
233 | /// 3. `BINDGEN_EXTRA_CLANG_ARGS` environment variable: whitespace separate |
234 | /// environment variable of arguments |
235 | /// |
236 | /// Clang arguments specific to your crate should be added via the |
237 | /// `clang_arg()`/`clang_args()` methods. |
238 | /// |
239 | /// End-users of the crate may need to set the `BINDGEN_EXTRA_CLANG_ARGS` environment variable to |
240 | /// add additional arguments. For example, to build against a different sysroot a user could set |
241 | /// `BINDGEN_EXTRA_CLANG_ARGS` to `--sysroot=/path/to/sysroot`. |
242 | /// |
243 | /// # Regular expression arguments |
244 | /// |
245 | /// Some [`Builder`] methods like the `allowlist_*` and `blocklist_*` family of methods allow |
246 | /// regular expressions as arguments. These regular expressions will be parenthesized and wrapped |
247 | /// in `^` and `$`. So if `<regex>` is passed as argument, the regular expression to be stored will |
248 | /// be `^(<regex>)$`. |
249 | /// |
250 | /// Releases of `bindgen` with a version lesser or equal to `0.62.0` used to accept the wildcard |
251 | /// pattern `*` as a valid regular expression. This behavior has been deprecated and the `.*` |
252 | /// pattern must be used instead. |
253 | #[derive (Debug, Default, Clone)] |
254 | pub struct Builder { |
255 | options: BindgenOptions, |
256 | } |
257 | |
258 | /// Construct a new [`Builder`](./struct.Builder.html). |
259 | pub fn builder() -> Builder { |
260 | Default::default() |
261 | } |
262 | |
263 | fn get_extra_clang_args() -> Vec<String> { |
264 | // Add any extra arguments from the environment to the clang command line. |
265 | let extra_clang_args: String = |
266 | match get_target_dependent_env_var("BINDGEN_EXTRA_CLANG_ARGS" ) { |
267 | None => return vec![], |
268 | Some(s: String) => s, |
269 | }; |
270 | // Try to parse it with shell quoting. If we fail, make it one single big argument. |
271 | if let Some(strings: Vec) = shlex::split(&extra_clang_args) { |
272 | return strings; |
273 | } |
274 | vec![extra_clang_args] |
275 | } |
276 | |
277 | impl Builder { |
278 | /// Generates the command line flags use for creating `Builder`. |
279 | pub fn command_line_flags(&self) -> Vec<String> { |
280 | let mut output_vector: Vec<String> = Vec::new(); |
281 | |
282 | if let Some(header) = self.options.input_headers.last().cloned() { |
283 | // Positional argument 'header' |
284 | output_vector.push(header); |
285 | } |
286 | |
287 | output_vector.push("--rust-target" .into()); |
288 | output_vector.push(self.options.rust_target.into()); |
289 | |
290 | // FIXME(emilio): This is a bit hacky, maybe we should stop re-using the |
291 | // RustFeatures to store the "disable_untagged_union" call, and make it |
292 | // a different flag that we check elsewhere / in generate(). |
293 | if !self.options.rust_features.untagged_union && |
294 | RustFeatures::from(self.options.rust_target).untagged_union |
295 | { |
296 | output_vector.push("--disable-untagged-union" .into()); |
297 | } |
298 | |
299 | if self.options.default_enum_style != Default::default() { |
300 | output_vector.push("--default-enum-style" .into()); |
301 | output_vector.push( |
302 | match self.options.default_enum_style { |
303 | codegen::EnumVariation::Rust { |
304 | non_exhaustive: false, |
305 | } => "rust" , |
306 | codegen::EnumVariation::Rust { |
307 | non_exhaustive: true, |
308 | } => "rust_non_exhaustive" , |
309 | codegen::EnumVariation::NewType { |
310 | is_bitfield: true, |
311 | .. |
312 | } => "bitfield" , |
313 | codegen::EnumVariation::NewType { |
314 | is_bitfield: false, |
315 | is_global, |
316 | } => { |
317 | if is_global { |
318 | "newtype_global" |
319 | } else { |
320 | "newtype" |
321 | } |
322 | } |
323 | codegen::EnumVariation::Consts => "consts" , |
324 | codegen::EnumVariation::ModuleConsts => "moduleconsts" , |
325 | } |
326 | .into(), |
327 | ) |
328 | } |
329 | |
330 | if self.options.default_macro_constant_type != Default::default() { |
331 | output_vector.push("--default-macro-constant-type" .into()); |
332 | output_vector |
333 | .push(self.options.default_macro_constant_type.as_str().into()); |
334 | } |
335 | |
336 | if self.options.default_alias_style != Default::default() { |
337 | output_vector.push("--default-alias-style" .into()); |
338 | output_vector |
339 | .push(self.options.default_alias_style.as_str().into()); |
340 | } |
341 | |
342 | if self.options.default_non_copy_union_style != Default::default() { |
343 | output_vector.push("--default-non-copy-union-style" .into()); |
344 | output_vector.push( |
345 | self.options.default_non_copy_union_style.as_str().into(), |
346 | ); |
347 | } |
348 | |
349 | let regex_sets = &[ |
350 | (&self.options.bitfield_enums, "--bitfield-enum" ), |
351 | (&self.options.newtype_enums, "--newtype-enum" ), |
352 | (&self.options.newtype_global_enums, "--newtype-global-enum" ), |
353 | (&self.options.rustified_enums, "--rustified-enum" ), |
354 | ( |
355 | &self.options.rustified_non_exhaustive_enums, |
356 | "--rustified-enum-non-exhaustive" , |
357 | ), |
358 | ( |
359 | &self.options.constified_enum_modules, |
360 | "--constified-enum-module" , |
361 | ), |
362 | (&self.options.constified_enums, "--constified-enum" ), |
363 | (&self.options.type_alias, "--type-alias" ), |
364 | (&self.options.new_type_alias, "--new-type-alias" ), |
365 | (&self.options.new_type_alias_deref, "--new-type-alias-deref" ), |
366 | ( |
367 | &self.options.bindgen_wrapper_union, |
368 | "--bindgen-wrapper-union" , |
369 | ), |
370 | (&self.options.manually_drop_union, "--manually-drop-union" ), |
371 | (&self.options.blocklisted_types, "--blocklist-type" ), |
372 | (&self.options.blocklisted_functions, "--blocklist-function" ), |
373 | (&self.options.blocklisted_items, "--blocklist-item" ), |
374 | (&self.options.blocklisted_files, "--blocklist-file" ), |
375 | (&self.options.opaque_types, "--opaque-type" ), |
376 | (&self.options.allowlisted_functions, "--allowlist-function" ), |
377 | (&self.options.allowlisted_types, "--allowlist-type" ), |
378 | (&self.options.allowlisted_vars, "--allowlist-var" ), |
379 | (&self.options.allowlisted_files, "--allowlist-file" ), |
380 | (&self.options.no_partialeq_types, "--no-partialeq" ), |
381 | (&self.options.no_copy_types, "--no-copy" ), |
382 | (&self.options.no_debug_types, "--no-debug" ), |
383 | (&self.options.no_default_types, "--no-default" ), |
384 | (&self.options.no_hash_types, "--no-hash" ), |
385 | (&self.options.must_use_types, "--must-use-type" ), |
386 | ]; |
387 | |
388 | for (set, flag) in regex_sets { |
389 | for item in set.get_items() { |
390 | output_vector.push((*flag).to_owned()); |
391 | output_vector.push(item.to_owned()); |
392 | } |
393 | } |
394 | |
395 | for (abi, set) in &self.options.abi_overrides { |
396 | for item in set.get_items() { |
397 | output_vector.push("--override-abi" .to_owned()); |
398 | output_vector.push(format!(" {}= {}" , item, abi)); |
399 | } |
400 | } |
401 | |
402 | if !self.options.layout_tests { |
403 | output_vector.push("--no-layout-tests" .into()); |
404 | } |
405 | |
406 | if self.options.impl_debug { |
407 | output_vector.push("--impl-debug" .into()); |
408 | } |
409 | |
410 | if self.options.impl_partialeq { |
411 | output_vector.push("--impl-partialeq" .into()); |
412 | } |
413 | |
414 | if !self.options.derive_copy { |
415 | output_vector.push("--no-derive-copy" .into()); |
416 | } |
417 | |
418 | if !self.options.derive_debug { |
419 | output_vector.push("--no-derive-debug" .into()); |
420 | } |
421 | |
422 | if !self.options.derive_default { |
423 | output_vector.push("--no-derive-default" .into()); |
424 | } else { |
425 | output_vector.push("--with-derive-default" .into()); |
426 | } |
427 | |
428 | if self.options.derive_hash { |
429 | output_vector.push("--with-derive-hash" .into()); |
430 | } |
431 | |
432 | if self.options.derive_partialord { |
433 | output_vector.push("--with-derive-partialord" .into()); |
434 | } |
435 | |
436 | if self.options.derive_ord { |
437 | output_vector.push("--with-derive-ord" .into()); |
438 | } |
439 | |
440 | if self.options.derive_partialeq { |
441 | output_vector.push("--with-derive-partialeq" .into()); |
442 | } |
443 | |
444 | if self.options.derive_eq { |
445 | output_vector.push("--with-derive-eq" .into()); |
446 | } |
447 | |
448 | if self.options.time_phases { |
449 | output_vector.push("--time-phases" .into()); |
450 | } |
451 | |
452 | if !self.options.generate_comments { |
453 | output_vector.push("--no-doc-comments" .into()); |
454 | } |
455 | |
456 | if !self.options.allowlist_recursively { |
457 | output_vector.push("--no-recursive-allowlist" .into()); |
458 | } |
459 | |
460 | if self.options.objc_extern_crate { |
461 | output_vector.push("--objc-extern-crate" .into()); |
462 | } |
463 | |
464 | if self.options.generate_block { |
465 | output_vector.push("--generate-block" .into()); |
466 | } |
467 | |
468 | if self.options.block_extern_crate { |
469 | output_vector.push("--block-extern-crate" .into()); |
470 | } |
471 | |
472 | if self.options.builtins { |
473 | output_vector.push("--builtins" .into()); |
474 | } |
475 | |
476 | if let Some(ref prefix) = self.options.ctypes_prefix { |
477 | output_vector.push("--ctypes-prefix" .into()); |
478 | output_vector.push(prefix.clone()); |
479 | } |
480 | |
481 | if self.options.anon_fields_prefix != DEFAULT_ANON_FIELDS_PREFIX { |
482 | output_vector.push("--anon-fields-prefix" .into()); |
483 | output_vector.push(self.options.anon_fields_prefix.clone()); |
484 | } |
485 | |
486 | if self.options.emit_ast { |
487 | output_vector.push("--emit-clang-ast" .into()); |
488 | } |
489 | |
490 | if self.options.emit_ir { |
491 | output_vector.push("--emit-ir" .into()); |
492 | } |
493 | if let Some(ref graph) = self.options.emit_ir_graphviz { |
494 | output_vector.push("--emit-ir-graphviz" .into()); |
495 | output_vector.push(graph.clone()) |
496 | } |
497 | if self.options.enable_cxx_namespaces { |
498 | output_vector.push("--enable-cxx-namespaces" .into()); |
499 | } |
500 | if self.options.enable_function_attribute_detection { |
501 | output_vector.push("--enable-function-attribute-detection" .into()); |
502 | } |
503 | if self.options.disable_name_namespacing { |
504 | output_vector.push("--disable-name-namespacing" .into()); |
505 | } |
506 | if self.options.disable_nested_struct_naming { |
507 | output_vector.push("--disable-nested-struct-naming" .into()); |
508 | } |
509 | |
510 | if self.options.disable_header_comment { |
511 | output_vector.push("--disable-header-comment" .into()); |
512 | } |
513 | |
514 | if !self.options.codegen_config.functions() { |
515 | output_vector.push("--ignore-functions" .into()); |
516 | } |
517 | |
518 | output_vector.push("--generate" .into()); |
519 | |
520 | //Temporary placeholder for below 4 options |
521 | let mut options: Vec<String> = Vec::new(); |
522 | if self.options.codegen_config.functions() { |
523 | options.push("functions" .into()); |
524 | } |
525 | if self.options.codegen_config.types() { |
526 | options.push("types" .into()); |
527 | } |
528 | if self.options.codegen_config.vars() { |
529 | options.push("vars" .into()); |
530 | } |
531 | if self.options.codegen_config.methods() { |
532 | options.push("methods" .into()); |
533 | } |
534 | if self.options.codegen_config.constructors() { |
535 | options.push("constructors" .into()); |
536 | } |
537 | if self.options.codegen_config.destructors() { |
538 | options.push("destructors" .into()); |
539 | } |
540 | |
541 | output_vector.push(options.join("," )); |
542 | |
543 | if !self.options.codegen_config.methods() { |
544 | output_vector.push("--ignore-methods" .into()); |
545 | } |
546 | |
547 | if !self.options.convert_floats { |
548 | output_vector.push("--no-convert-floats" .into()); |
549 | } |
550 | |
551 | if !self.options.prepend_enum_name { |
552 | output_vector.push("--no-prepend-enum-name" .into()); |
553 | } |
554 | |
555 | if self.options.fit_macro_constants { |
556 | output_vector.push("--fit-macro-constant-types" .into()); |
557 | } |
558 | |
559 | if self.options.array_pointers_in_arguments { |
560 | output_vector.push("--use-array-pointers-in-arguments" .into()); |
561 | } |
562 | |
563 | if let Some(ref wasm_import_module_name) = |
564 | self.options.wasm_import_module_name |
565 | { |
566 | output_vector.push("--wasm-import-module-name" .into()); |
567 | output_vector.push(wasm_import_module_name.clone()); |
568 | } |
569 | |
570 | for line in &self.options.raw_lines { |
571 | output_vector.push("--raw-line" .into()); |
572 | output_vector.push(line.clone()); |
573 | } |
574 | |
575 | for (module, lines) in &self.options.module_lines { |
576 | for line in lines.iter() { |
577 | output_vector.push("--module-raw-line" .into()); |
578 | output_vector.push(module.clone()); |
579 | output_vector.push(line.clone()); |
580 | } |
581 | } |
582 | |
583 | if self.options.use_core { |
584 | output_vector.push("--use-core" .into()); |
585 | } |
586 | |
587 | if self.options.conservative_inline_namespaces { |
588 | output_vector.push("--conservative-inline-namespaces" .into()); |
589 | } |
590 | |
591 | if self.options.generate_inline_functions { |
592 | output_vector.push("--generate-inline-functions" .into()); |
593 | } |
594 | |
595 | if !self.options.record_matches { |
596 | output_vector.push("--no-record-matches" .into()); |
597 | } |
598 | |
599 | if !self.options.size_t_is_usize { |
600 | output_vector.push("--no-size_t-is-usize" .into()); |
601 | } |
602 | |
603 | if !self.options.rustfmt_bindings { |
604 | output_vector.push("--no-rustfmt-bindings" .into()); |
605 | } |
606 | |
607 | if let Some(path) = self |
608 | .options |
609 | .rustfmt_configuration_file |
610 | .as_ref() |
611 | .and_then(|f| f.to_str()) |
612 | { |
613 | output_vector.push("--rustfmt-configuration-file" .into()); |
614 | output_vector.push(path.into()); |
615 | } |
616 | |
617 | if let Some(ref name) = self.options.dynamic_library_name { |
618 | output_vector.push("--dynamic-loading" .into()); |
619 | output_vector.push(name.clone()); |
620 | } |
621 | |
622 | if self.options.dynamic_link_require_all { |
623 | output_vector.push("--dynamic-link-require-all" .into()); |
624 | } |
625 | |
626 | if self.options.respect_cxx_access_specs { |
627 | output_vector.push("--respect-cxx-access-specs" .into()); |
628 | } |
629 | |
630 | if self.options.translate_enum_integer_types { |
631 | output_vector.push("--translate-enum-integer-types" .into()); |
632 | } |
633 | |
634 | if self.options.c_naming { |
635 | output_vector.push("--c-naming" .into()); |
636 | } |
637 | |
638 | if self.options.force_explicit_padding { |
639 | output_vector.push("--explicit-padding" .into()); |
640 | } |
641 | |
642 | if self.options.vtable_generation { |
643 | output_vector.push("--vtable-generation" .into()); |
644 | } |
645 | |
646 | if self.options.sort_semantically { |
647 | output_vector.push("--sort-semantically" .into()); |
648 | } |
649 | |
650 | if self.options.merge_extern_blocks { |
651 | output_vector.push("--merge-extern-blocks" .into()); |
652 | } |
653 | |
654 | if self.options.wrap_unsafe_ops { |
655 | output_vector.push("--wrap-unsafe-ops" .into()); |
656 | } |
657 | |
658 | #[cfg (feature = "cli" )] |
659 | for callbacks in &self.options.parse_callbacks { |
660 | output_vector.extend(callbacks.cli_args()); |
661 | } |
662 | if self.options.wrap_static_fns { |
663 | output_vector.push("--wrap-static-fns" .into()) |
664 | } |
665 | |
666 | if let Some(ref path) = self.options.wrap_static_fns_path { |
667 | output_vector.push("--wrap-static-fns-path" .into()); |
668 | output_vector.push(path.display().to_string()); |
669 | } |
670 | |
671 | if let Some(ref suffix) = self.options.wrap_static_fns_suffix { |
672 | output_vector.push("--wrap-static-fns-suffix" .into()); |
673 | output_vector.push(suffix.clone()); |
674 | } |
675 | |
676 | if cfg!(feature = "experimental" ) { |
677 | output_vector.push("--experimental" .into()); |
678 | } |
679 | |
680 | // Add clang arguments |
681 | |
682 | output_vector.push("--" .into()); |
683 | |
684 | if !self.options.clang_args.is_empty() { |
685 | output_vector.extend(self.options.clang_args.iter().cloned()); |
686 | } |
687 | |
688 | // To pass more than one header, we need to pass all but the last |
689 | // header via the `-include` clang arg |
690 | for header in &self.options.input_headers |
691 | [..self.options.input_headers.len().saturating_sub(1)] |
692 | { |
693 | output_vector.push("-include" .to_string()); |
694 | output_vector.push(header.clone()); |
695 | } |
696 | |
697 | output_vector |
698 | } |
699 | |
700 | /// Add an input C/C++ header to generate bindings for. |
701 | /// |
702 | /// This can be used to generate bindings to a single header: |
703 | /// |
704 | /// ```ignore |
705 | /// let bindings = bindgen::Builder::default() |
706 | /// .header("input.h" ) |
707 | /// .generate() |
708 | /// .unwrap(); |
709 | /// ``` |
710 | /// |
711 | /// Or you can invoke it multiple times to generate bindings to multiple |
712 | /// headers: |
713 | /// |
714 | /// ```ignore |
715 | /// let bindings = bindgen::Builder::default() |
716 | /// .header("first.h" ) |
717 | /// .header("second.h" ) |
718 | /// .header("third.h" ) |
719 | /// .generate() |
720 | /// .unwrap(); |
721 | /// ``` |
722 | pub fn header<T: Into<String>>(mut self, header: T) -> Builder { |
723 | self.options.input_headers.push(header.into()); |
724 | self |
725 | } |
726 | |
727 | /// Add a depfile output which will be written alongside the generated bindings. |
728 | pub fn depfile<H: Into<String>, D: Into<PathBuf>>( |
729 | mut self, |
730 | output_module: H, |
731 | depfile: D, |
732 | ) -> Builder { |
733 | self.options.depfile = Some(deps::DepfileSpec { |
734 | output_module: output_module.into(), |
735 | depfile_path: depfile.into(), |
736 | }); |
737 | self |
738 | } |
739 | |
740 | /// Add `contents` as an input C/C++ header named `name`. |
741 | /// |
742 | /// The file `name` will be added to the clang arguments. |
743 | pub fn header_contents(mut self, name: &str, contents: &str) -> Builder { |
744 | // Apparently clang relies on having virtual FS correspondent to |
745 | // the real one, so we need absolute paths here |
746 | let absolute_path = env::current_dir() |
747 | .expect("Cannot retrieve current directory" ) |
748 | .join(name) |
749 | .to_str() |
750 | .expect("Cannot convert current directory name to string" ) |
751 | .to_owned(); |
752 | self.options |
753 | .input_header_contents |
754 | .push((absolute_path, contents.into())); |
755 | self |
756 | } |
757 | |
758 | /// Specify the rust target |
759 | /// |
760 | /// The default is the latest stable Rust version |
761 | pub fn rust_target(mut self, rust_target: RustTarget) -> Self { |
762 | #[allow (deprecated)] |
763 | if rust_target <= RustTarget::Stable_1_30 { |
764 | warn!( |
765 | "The {} rust target is deprecated. If you have a good reason to use this target please report it at https://github.com/rust-lang/rust-bindgen/issues" , |
766 | String::from(rust_target) |
767 | ); |
768 | } |
769 | self.options.set_rust_target(rust_target); |
770 | self |
771 | } |
772 | |
773 | /// Disable support for native Rust unions, if supported. |
774 | pub fn disable_untagged_union(mut self) -> Self { |
775 | self.options.rust_features.untagged_union = false; |
776 | self |
777 | } |
778 | |
779 | /// Disable insertion of bindgen's version identifier into generated |
780 | /// bindings. |
781 | pub fn disable_header_comment(mut self) -> Self { |
782 | self.options.disable_header_comment = true; |
783 | self |
784 | } |
785 | |
786 | /// Set the output graphviz file. |
787 | pub fn emit_ir_graphviz<T: Into<String>>(mut self, path: T) -> Builder { |
788 | let path = path.into(); |
789 | self.options.emit_ir_graphviz = Some(path); |
790 | self |
791 | } |
792 | |
793 | /// Whether the generated bindings should contain documentation comments |
794 | /// (docstrings) or not. This is set to true by default. |
795 | /// |
796 | /// Note that clang by default excludes comments from system headers, pass |
797 | /// `-fretain-comments-from-system-headers` as |
798 | /// [`clang_arg`][Builder::clang_arg] to include them. It can also be told |
799 | /// to process all comments (not just documentation ones) using the |
800 | /// `-fparse-all-comments` flag. See [slides on clang comment parsing]( |
801 | /// https://llvm.org/devmtg/2012-11/Gribenko_CommentParsing.pdf) for |
802 | /// background and examples. |
803 | pub fn generate_comments(mut self, doit: bool) -> Self { |
804 | self.options.generate_comments = doit; |
805 | self |
806 | } |
807 | |
808 | /// Whether to allowlist recursively or not. Defaults to true. |
809 | /// |
810 | /// Given that we have explicitly allowlisted the "initiate_dance_party" |
811 | /// function in this C header: |
812 | /// |
813 | /// ```c |
814 | /// typedef struct MoonBoots { |
815 | /// int bouncy_level; |
816 | /// } MoonBoots; |
817 | /// |
818 | /// void initiate_dance_party(MoonBoots* boots); |
819 | /// ``` |
820 | /// |
821 | /// We would normally generate bindings to both the `initiate_dance_party` |
822 | /// function and the `MoonBoots` struct that it transitively references. By |
823 | /// configuring with `allowlist_recursively(false)`, `bindgen` will not emit |
824 | /// bindings for anything except the explicitly allowlisted items, and there |
825 | /// would be no emitted struct definition for `MoonBoots`. However, the |
826 | /// `initiate_dance_party` function would still reference `MoonBoots`! |
827 | /// |
828 | /// **Disabling this feature will almost certainly cause `bindgen` to emit |
829 | /// bindings that will not compile!** If you disable this feature, then it |
830 | /// is *your* responsibility to provide definitions for every type that is |
831 | /// referenced from an explicitly allowlisted item. One way to provide the |
832 | /// definitions is by using the [`Builder::raw_line`](#method.raw_line) |
833 | /// method, another would be to define them in Rust and then `include!(...)` |
834 | /// the bindings immediately afterwards. |
835 | pub fn allowlist_recursively(mut self, doit: bool) -> Self { |
836 | self.options.allowlist_recursively = doit; |
837 | self |
838 | } |
839 | |
840 | /// Generate `#[macro_use] extern crate objc;` instead of `use objc;` |
841 | /// in the prologue of the files generated from objective-c files |
842 | pub fn objc_extern_crate(mut self, doit: bool) -> Self { |
843 | self.options.objc_extern_crate = doit; |
844 | self |
845 | } |
846 | |
847 | /// Generate proper block signatures instead of void pointers. |
848 | pub fn generate_block(mut self, doit: bool) -> Self { |
849 | self.options.generate_block = doit; |
850 | self |
851 | } |
852 | |
853 | /// Generate `#[macro_use] extern crate block;` instead of `use block;` |
854 | /// in the prologue of the files generated from apple block files |
855 | pub fn block_extern_crate(mut self, doit: bool) -> Self { |
856 | self.options.block_extern_crate = doit; |
857 | self |
858 | } |
859 | |
860 | /// Whether to use the clang-provided name mangling. This is true by default |
861 | /// and probably needed for C++ features. |
862 | /// |
863 | /// However, some old libclang versions seem to return incorrect results in |
864 | /// some cases for non-mangled functions, see [1], so we allow disabling it. |
865 | /// |
866 | /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 |
867 | pub fn trust_clang_mangling(mut self, doit: bool) -> Self { |
868 | self.options.enable_mangling = doit; |
869 | self |
870 | } |
871 | |
872 | fn_with_regex_arg! { |
873 | /// Hide the given type from the generated bindings. Regular expressions are |
874 | /// supported. |
875 | /// |
876 | /// To blocklist types prefixed with "mylib" use `"mylib_.*"`. |
877 | pub fn blocklist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { |
878 | self.options.blocklisted_types.insert(arg); |
879 | self |
880 | } |
881 | } |
882 | |
883 | fn_with_regex_arg! { |
884 | /// Hide the given function from the generated bindings. Regular expressions |
885 | /// are supported. |
886 | /// |
887 | /// Methods can be blocklisted by prefixing the name of the type implementing |
888 | /// them followed by an underscore. So if `Foo` has a method `bar`, it can |
889 | /// be blocklisted as `Foo_bar`. |
890 | /// |
891 | /// To blocklist functions prefixed with "mylib" use `"mylib_.*"`. |
892 | pub fn blocklist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { |
893 | self.options.blocklisted_functions.insert(arg); |
894 | self |
895 | } |
896 | } |
897 | |
898 | fn_with_regex_arg! { |
899 | /// Hide the given item from the generated bindings, regardless of |
900 | /// whether it's a type, function, module, etc. Regular |
901 | /// expressions are supported. |
902 | /// |
903 | /// To blocklist items prefixed with "mylib" use `"mylib_.*"`. |
904 | pub fn blocklist_item<T: AsRef<str>>(mut self, arg: T) -> Builder { |
905 | self.options.blocklisted_items.insert(arg); |
906 | self |
907 | } |
908 | } |
909 | |
910 | fn_with_regex_arg! { |
911 | /// Hide any contents of the given file from the generated bindings, |
912 | /// regardless of whether it's a type, function, module etc. |
913 | pub fn blocklist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { |
914 | self.options.blocklisted_files.insert(arg); |
915 | self |
916 | } |
917 | } |
918 | |
919 | fn_with_regex_arg! { |
920 | /// Treat the given type as opaque in the generated bindings. Regular |
921 | /// expressions are supported. |
922 | /// |
923 | /// To change types prefixed with "mylib" into opaque, use `"mylib_.*"`. |
924 | pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder { |
925 | self.options.opaque_types.insert(arg); |
926 | self |
927 | } |
928 | } |
929 | |
930 | fn_with_regex_arg! { |
931 | /// Allowlist the given type so that it (and all types that it transitively |
932 | /// refers to) appears in the generated bindings. Regular expressions are |
933 | /// supported. |
934 | /// |
935 | /// To allowlist types prefixed with "mylib" use `"mylib_.*"`. |
936 | pub fn allowlist_type<T: AsRef<str>>(mut self, arg: T) -> Builder { |
937 | self.options.allowlisted_types.insert(arg); |
938 | self |
939 | } |
940 | } |
941 | |
942 | fn_with_regex_arg! { |
943 | /// Allowlist the given function so that it (and all types that it |
944 | /// transitively refers to) appears in the generated bindings. Regular |
945 | /// expressions are supported. |
946 | /// |
947 | /// Methods can be allowlisted by prefixing the name of the type |
948 | /// implementing them followed by an underscore. So if `Foo` has a method |
949 | /// `bar`, it can be allowlisted as `Foo_bar`. |
950 | /// |
951 | /// To allowlist functions prefixed with "mylib" use `"mylib_.*"`. |
952 | pub fn allowlist_function<T: AsRef<str>>(mut self, arg: T) -> Builder { |
953 | self.options.allowlisted_functions.insert(arg); |
954 | self |
955 | } |
956 | } |
957 | |
958 | fn_with_regex_arg! { |
959 | /// Allowlist the given variable so that it (and all types that it |
960 | /// transitively refers to) appears in the generated bindings. Regular |
961 | /// expressions are supported. |
962 | /// |
963 | /// To allowlist variables prefixed with "mylib" use `"mylib_.*"`. |
964 | pub fn allowlist_var<T: AsRef<str>>(mut self, arg: T) -> Builder { |
965 | self.options.allowlisted_vars.insert(arg); |
966 | self |
967 | } |
968 | } |
969 | |
970 | fn_with_regex_arg! { |
971 | /// Allowlist the given file so that its contents appear in the generated bindings. |
972 | pub fn allowlist_file<T: AsRef<str>>(mut self, arg: T) -> Builder { |
973 | self.options.allowlisted_files.insert(arg); |
974 | self |
975 | } |
976 | } |
977 | |
978 | /// Set the default style of code to generate for enums |
979 | pub fn default_enum_style( |
980 | mut self, |
981 | arg: codegen::EnumVariation, |
982 | ) -> Builder { |
983 | self.options.default_enum_style = arg; |
984 | self |
985 | } |
986 | |
987 | fn_with_regex_arg! { |
988 | /// Mark the given enum (or set of enums, if using a pattern) as being |
989 | /// bitfield-like. Regular expressions are supported. |
990 | /// |
991 | /// This makes bindgen generate a type that isn't a rust `enum`. Regular |
992 | /// expressions are supported. |
993 | /// |
994 | /// This is similar to the newtype enum style, but with the bitwise |
995 | /// operators implemented. |
996 | pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
997 | self.options.bitfield_enums.insert(arg); |
998 | self |
999 | } |
1000 | } |
1001 | |
1002 | fn_with_regex_arg! { |
1003 | /// Mark the given enum (or set of enums, if using a pattern) as a newtype. |
1004 | /// Regular expressions are supported. |
1005 | /// |
1006 | /// This makes bindgen generate a type that isn't a Rust `enum`. Regular |
1007 | /// expressions are supported. |
1008 | pub fn newtype_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1009 | self.options.newtype_enums.insert(arg); |
1010 | self |
1011 | } |
1012 | } |
1013 | |
1014 | fn_with_regex_arg! { |
1015 | /// Mark the given enum (or set of enums, if using a pattern) as a newtype |
1016 | /// whose variants are exposed as global constants. |
1017 | /// |
1018 | /// Regular expressions are supported. |
1019 | /// |
1020 | /// This makes bindgen generate a type that isn't a Rust `enum`. Regular |
1021 | /// expressions are supported. |
1022 | pub fn newtype_global_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1023 | self.options.newtype_global_enums.insert(arg); |
1024 | self |
1025 | } |
1026 | } |
1027 | |
1028 | fn_with_regex_arg! { |
1029 | /// Mark the given enum (or set of enums, if using a pattern) as a Rust |
1030 | /// enum. |
1031 | /// |
1032 | /// This makes bindgen generate enums instead of constants. Regular |
1033 | /// expressions are supported. |
1034 | /// |
1035 | /// **Use this with caution**, creating this in unsafe code |
1036 | /// (including FFI) with an invalid value will invoke undefined behaviour. |
1037 | /// You may want to use the newtype enum style instead. |
1038 | pub fn rustified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1039 | self.options.rustified_enums.insert(arg); |
1040 | self |
1041 | } |
1042 | } |
1043 | |
1044 | fn_with_regex_arg! { |
1045 | /// Mark the given enum (or set of enums, if using a pattern) as a Rust |
1046 | /// enum with the `#[non_exhaustive]` attribute. |
1047 | /// |
1048 | /// This makes bindgen generate enums instead of constants. Regular |
1049 | /// expressions are supported. |
1050 | /// |
1051 | /// **Use this with caution**, creating this in unsafe code |
1052 | /// (including FFI) with an invalid value will invoke undefined behaviour. |
1053 | /// You may want to use the newtype enum style instead. |
1054 | pub fn rustified_non_exhaustive_enum<T: AsRef<str>>( |
1055 | mut self, |
1056 | arg: T, |
1057 | ) -> Builder { |
1058 | self.options.rustified_non_exhaustive_enums.insert(arg); |
1059 | self |
1060 | } |
1061 | } |
1062 | |
1063 | fn_with_regex_arg! { |
1064 | /// Mark the given enum (or set of enums, if using a pattern) as a set of |
1065 | /// constants that are not to be put into a module. |
1066 | pub fn constified_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1067 | self.options.constified_enums.insert(arg); |
1068 | self |
1069 | } |
1070 | } |
1071 | |
1072 | fn_with_regex_arg! { |
1073 | /// Mark the given enum (or set of enums, if using a pattern) as a set of |
1074 | /// constants that should be put into a module. |
1075 | /// |
1076 | /// This makes bindgen generate modules containing constants instead of |
1077 | /// just constants. Regular expressions are supported. |
1078 | pub fn constified_enum_module<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1079 | self.options.constified_enum_modules.insert(arg); |
1080 | self |
1081 | } |
1082 | } |
1083 | |
1084 | /// Set the default type for macro constants |
1085 | pub fn default_macro_constant_type( |
1086 | mut self, |
1087 | arg: codegen::MacroTypeVariation, |
1088 | ) -> Builder { |
1089 | self.options.default_macro_constant_type = arg; |
1090 | self |
1091 | } |
1092 | |
1093 | /// Set the default style of code to generate for typedefs |
1094 | pub fn default_alias_style( |
1095 | mut self, |
1096 | arg: codegen::AliasVariation, |
1097 | ) -> Builder { |
1098 | self.options.default_alias_style = arg; |
1099 | self |
1100 | } |
1101 | |
1102 | fn_with_regex_arg! { |
1103 | /// Mark the given typedef alias (or set of aliases, if using a pattern) to |
1104 | /// use regular Rust type aliasing. |
1105 | /// |
1106 | /// This is the default behavior and should be used if `default_alias_style` |
1107 | /// was set to NewType or NewTypeDeref and you want to override it for a |
1108 | /// set of typedefs. |
1109 | pub fn type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1110 | self.options.type_alias.insert(arg); |
1111 | self |
1112 | } |
1113 | } |
1114 | |
1115 | fn_with_regex_arg! { |
1116 | /// Mark the given typedef alias (or set of aliases, if using a pattern) to |
1117 | /// be generated as a new type by having the aliased type be wrapped in a |
1118 | /// #[repr(transparent)] struct. |
1119 | /// |
1120 | /// Used to enforce stricter type checking. |
1121 | pub fn new_type_alias<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1122 | self.options.new_type_alias.insert(arg); |
1123 | self |
1124 | } |
1125 | } |
1126 | |
1127 | fn_with_regex_arg! { |
1128 | /// Mark the given typedef alias (or set of aliases, if using a pattern) to |
1129 | /// be generated as a new type by having the aliased type be wrapped in a |
1130 | /// #[repr(transparent)] struct and also have an automatically generated |
1131 | /// impl's of `Deref` and `DerefMut` to their aliased type. |
1132 | pub fn new_type_alias_deref<T: AsRef<str>>(mut self, arg: T) -> Builder { |
1133 | self.options.new_type_alias_deref.insert(arg); |
1134 | self |
1135 | } |
1136 | } |
1137 | |
1138 | /// Set the default style of code to generate for unions with a non-Copy member. |
1139 | pub fn default_non_copy_union_style( |
1140 | mut self, |
1141 | arg: codegen::NonCopyUnionStyle, |
1142 | ) -> Self { |
1143 | self.options.default_non_copy_union_style = arg; |
1144 | self |
1145 | } |
1146 | |
1147 | fn_with_regex_arg! { |
1148 | /// Mark the given union (or set of union, if using a pattern) to use |
1149 | /// a bindgen-generated wrapper for its members if at least one is non-Copy. |
1150 | pub fn bindgen_wrapper_union<T: AsRef<str>>(mut self, arg: T) -> Self { |
1151 | self.options.bindgen_wrapper_union.insert(arg); |
1152 | self |
1153 | } |
1154 | } |
1155 | |
1156 | fn_with_regex_arg! { |
1157 | /// Mark the given union (or set of union, if using a pattern) to use |
1158 | /// [`::core::mem::ManuallyDrop`] for its members if at least one is non-Copy. |
1159 | /// |
1160 | /// Note: `ManuallyDrop` was stabilized in Rust 1.20.0, do not use it if your |
1161 | /// MSRV is lower. |
1162 | pub fn manually_drop_union<T: AsRef<str>>(mut self, arg: T) -> Self { |
1163 | self.options.manually_drop_union.insert(arg); |
1164 | self |
1165 | } |
1166 | } |
1167 | |
1168 | fn_with_regex_arg! { |
1169 | /// Add a string to prepend to the generated bindings. The string is passed |
1170 | /// through without any modification. |
1171 | pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self { |
1172 | self.options.raw_lines.push(arg.into()); |
1173 | self |
1174 | } |
1175 | } |
1176 | |
1177 | /// Add a given line to the beginning of module `mod`. |
1178 | pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self |
1179 | where |
1180 | T: Into<String>, |
1181 | U: Into<String>, |
1182 | { |
1183 | self.options |
1184 | .module_lines |
1185 | .entry(mod_.into()) |
1186 | .or_insert_with(Vec::new) |
1187 | .push(line.into()); |
1188 | self |
1189 | } |
1190 | |
1191 | /// Add a given set of lines to the beginning of module `mod`. |
1192 | pub fn module_raw_lines<T, I>(mut self, mod_: T, lines: I) -> Self |
1193 | where |
1194 | T: Into<String>, |
1195 | I: IntoIterator, |
1196 | I::Item: Into<String>, |
1197 | { |
1198 | self.options |
1199 | .module_lines |
1200 | .entry(mod_.into()) |
1201 | .or_insert_with(Vec::new) |
1202 | .extend(lines.into_iter().map(Into::into)); |
1203 | self |
1204 | } |
1205 | |
1206 | /// Add an argument to be passed straight through to clang. |
1207 | pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder { |
1208 | self.options.clang_args.push(arg.into()); |
1209 | self |
1210 | } |
1211 | |
1212 | /// Add arguments to be passed straight through to clang. |
1213 | pub fn clang_args<I>(mut self, iter: I) -> Builder |
1214 | where |
1215 | I: IntoIterator, |
1216 | I::Item: AsRef<str>, |
1217 | { |
1218 | for arg in iter { |
1219 | self = self.clang_arg(arg.as_ref()) |
1220 | } |
1221 | self |
1222 | } |
1223 | |
1224 | /// Emit bindings for builtin definitions (for example `__builtin_va_list`) |
1225 | /// in the generated Rust. |
1226 | pub fn emit_builtins(mut self) -> Builder { |
1227 | self.options.builtins = true; |
1228 | self |
1229 | } |
1230 | |
1231 | /// Avoid converting floats to `f32`/`f64` by default. |
1232 | pub fn no_convert_floats(mut self) -> Self { |
1233 | self.options.convert_floats = false; |
1234 | self |
1235 | } |
1236 | |
1237 | /// Set whether layout tests should be generated. |
1238 | pub fn layout_tests(mut self, doit: bool) -> Self { |
1239 | self.options.layout_tests = doit; |
1240 | self |
1241 | } |
1242 | |
1243 | /// Set whether `Debug` should be implemented, if it can not be derived automatically. |
1244 | pub fn impl_debug(mut self, doit: bool) -> Self { |
1245 | self.options.impl_debug = doit; |
1246 | self |
1247 | } |
1248 | |
1249 | /// Set whether `PartialEq` should be implemented, if it can not be derived automatically. |
1250 | pub fn impl_partialeq(mut self, doit: bool) -> Self { |
1251 | self.options.impl_partialeq = doit; |
1252 | self |
1253 | } |
1254 | |
1255 | /// Set whether `Copy` should be derived by default. |
1256 | pub fn derive_copy(mut self, doit: bool) -> Self { |
1257 | self.options.derive_copy = doit; |
1258 | self |
1259 | } |
1260 | |
1261 | /// Set whether `Debug` should be derived by default. |
1262 | pub fn derive_debug(mut self, doit: bool) -> Self { |
1263 | self.options.derive_debug = doit; |
1264 | self |
1265 | } |
1266 | |
1267 | /// Set whether `Default` should be derived by default. |
1268 | pub fn derive_default(mut self, doit: bool) -> Self { |
1269 | self.options.derive_default = doit; |
1270 | self |
1271 | } |
1272 | |
1273 | /// Set whether `Hash` should be derived by default. |
1274 | pub fn derive_hash(mut self, doit: bool) -> Self { |
1275 | self.options.derive_hash = doit; |
1276 | self |
1277 | } |
1278 | |
1279 | /// Set whether `PartialOrd` should be derived by default. |
1280 | /// If we don't compute partialord, we also cannot compute |
1281 | /// ord. Set the derive_ord to `false` when doit is `false`. |
1282 | pub fn derive_partialord(mut self, doit: bool) -> Self { |
1283 | self.options.derive_partialord = doit; |
1284 | if !doit { |
1285 | self.options.derive_ord = false; |
1286 | } |
1287 | self |
1288 | } |
1289 | |
1290 | /// Set whether `Ord` should be derived by default. |
1291 | /// We can't compute `Ord` without computing `PartialOrd`, |
1292 | /// so we set the same option to derive_partialord. |
1293 | pub fn derive_ord(mut self, doit: bool) -> Self { |
1294 | self.options.derive_ord = doit; |
1295 | self.options.derive_partialord = doit; |
1296 | self |
1297 | } |
1298 | |
1299 | /// Set whether `PartialEq` should be derived by default. |
1300 | /// |
1301 | /// If we don't derive `PartialEq`, we also cannot derive `Eq`, so deriving |
1302 | /// `Eq` is also disabled when `doit` is `false`. |
1303 | pub fn derive_partialeq(mut self, doit: bool) -> Self { |
1304 | self.options.derive_partialeq = doit; |
1305 | if !doit { |
1306 | self.options.derive_eq = false; |
1307 | } |
1308 | self |
1309 | } |
1310 | |
1311 | /// Set whether `Eq` should be derived by default. |
1312 | /// |
1313 | /// We can't derive `Eq` without also deriving `PartialEq`, so we also |
1314 | /// enable deriving `PartialEq` when `doit` is `true`. |
1315 | pub fn derive_eq(mut self, doit: bool) -> Self { |
1316 | self.options.derive_eq = doit; |
1317 | if doit { |
1318 | self.options.derive_partialeq = doit; |
1319 | } |
1320 | self |
1321 | } |
1322 | |
1323 | /// Set whether or not to time bindgen phases, and print information to |
1324 | /// stderr. |
1325 | pub fn time_phases(mut self, doit: bool) -> Self { |
1326 | self.options.time_phases = doit; |
1327 | self |
1328 | } |
1329 | |
1330 | /// Emit Clang AST. |
1331 | pub fn emit_clang_ast(mut self) -> Builder { |
1332 | self.options.emit_ast = true; |
1333 | self |
1334 | } |
1335 | |
1336 | /// Emit IR. |
1337 | pub fn emit_ir(mut self) -> Builder { |
1338 | self.options.emit_ir = true; |
1339 | self |
1340 | } |
1341 | |
1342 | /// Enable C++ namespaces. |
1343 | pub fn enable_cxx_namespaces(mut self) -> Builder { |
1344 | self.options.enable_cxx_namespaces = true; |
1345 | self |
1346 | } |
1347 | |
1348 | /// Enable detecting must_use attributes on C functions. |
1349 | /// |
1350 | /// This is quite slow in some cases (see #1465), so it's disabled by |
1351 | /// default. |
1352 | /// |
1353 | /// Note that for this to do something meaningful for now at least, the rust |
1354 | /// target version has to have support for `#[must_use]`. |
1355 | pub fn enable_function_attribute_detection(mut self) -> Self { |
1356 | self.options.enable_function_attribute_detection = true; |
1357 | self |
1358 | } |
1359 | |
1360 | /// Disable name auto-namespacing. |
1361 | /// |
1362 | /// By default, bindgen mangles names like `foo::bar::Baz` to look like |
1363 | /// `foo_bar_Baz` instead of just `Baz`. |
1364 | /// |
1365 | /// This method disables that behavior. |
1366 | /// |
1367 | /// Note that this intentionally does not change the names used for |
1368 | /// allowlisting and blocklisting, which should still be mangled with the |
1369 | /// namespaces. |
1370 | /// |
1371 | /// Note, also, that this option may cause bindgen to generate duplicate |
1372 | /// names. |
1373 | pub fn disable_name_namespacing(mut self) -> Builder { |
1374 | self.options.disable_name_namespacing = true; |
1375 | self |
1376 | } |
1377 | |
1378 | /// Disable nested struct naming. |
1379 | /// |
1380 | /// The following structs have different names for C and C++. In case of C |
1381 | /// they are visible as `foo` and `bar`. In case of C++ they are visible as |
1382 | /// `foo` and `foo::bar`. |
1383 | /// |
1384 | /// ```c |
1385 | /// struct foo { |
1386 | /// struct bar { |
1387 | /// } b; |
1388 | /// }; |
1389 | /// ``` |
1390 | /// |
1391 | /// Bindgen wants to avoid duplicate names by default so it follows C++ naming |
1392 | /// and it generates `foo`/`foo_bar` instead of just `foo`/`bar`. |
1393 | /// |
1394 | /// This method disables this behavior and it is indented to be used only |
1395 | /// for headers that were written for C. |
1396 | pub fn disable_nested_struct_naming(mut self) -> Builder { |
1397 | self.options.disable_nested_struct_naming = true; |
1398 | self |
1399 | } |
1400 | |
1401 | /// Treat inline namespaces conservatively. |
1402 | /// |
1403 | /// This is tricky, because in C++ is technically legal to override an item |
1404 | /// defined in an inline namespace: |
1405 | /// |
1406 | /// ```cpp |
1407 | /// inline namespace foo { |
1408 | /// using Bar = int; |
1409 | /// } |
1410 | /// using Bar = long; |
1411 | /// ``` |
1412 | /// |
1413 | /// Even though referencing `Bar` is a compiler error. |
1414 | /// |
1415 | /// We want to support this (arguably esoteric) use case, but we don't want |
1416 | /// to make the rest of bindgen users pay an usability penalty for that. |
1417 | /// |
1418 | /// To support this, we need to keep all the inline namespaces around, but |
1419 | /// then bindgen usage is a bit more difficult, because you cannot |
1420 | /// reference, e.g., `std::string` (you'd need to use the proper inline |
1421 | /// namespace). |
1422 | /// |
1423 | /// We could complicate a lot of the logic to detect name collisions, and if |
1424 | /// not detected generate a `pub use inline_ns::*` or something like that. |
1425 | /// |
1426 | /// That's probably something we can do if we see this option is needed in a |
1427 | /// lot of cases, to improve it's usability, but my guess is that this is |
1428 | /// not going to be too useful. |
1429 | pub fn conservative_inline_namespaces(mut self) -> Builder { |
1430 | self.options.conservative_inline_namespaces = true; |
1431 | self |
1432 | } |
1433 | |
1434 | /// Whether inline functions should be generated or not. |
1435 | /// |
1436 | /// Note that they will usually not work. However you can use |
1437 | /// `-fkeep-inline-functions` or `-fno-inline-functions` if you are |
1438 | /// responsible of compiling the library to make them callable. |
1439 | pub fn generate_inline_functions(mut self, doit: bool) -> Self { |
1440 | self.options.generate_inline_functions = doit; |
1441 | self |
1442 | } |
1443 | |
1444 | /// Ignore functions. |
1445 | pub fn ignore_functions(mut self) -> Builder { |
1446 | self.options.codegen_config.remove(CodegenConfig::FUNCTIONS); |
1447 | self |
1448 | } |
1449 | |
1450 | /// Ignore methods. |
1451 | pub fn ignore_methods(mut self) -> Builder { |
1452 | self.options.codegen_config.remove(CodegenConfig::METHODS); |
1453 | self |
1454 | } |
1455 | |
1456 | /// Use core instead of libstd in the generated bindings. |
1457 | pub fn use_core(mut self) -> Builder { |
1458 | self.options.use_core = true; |
1459 | self |
1460 | } |
1461 | |
1462 | /// Use the given prefix for the raw types instead of `::std::os::raw`. |
1463 | pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { |
1464 | self.options.ctypes_prefix = Some(prefix.into()); |
1465 | self |
1466 | } |
1467 | |
1468 | /// Use the given prefix for the anon fields. |
1469 | pub fn anon_fields_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { |
1470 | self.options.anon_fields_prefix = prefix.into(); |
1471 | self |
1472 | } |
1473 | |
1474 | /// Allows configuring types in different situations, see the |
1475 | /// [`ParseCallbacks`](./callbacks/trait.ParseCallbacks.html) documentation. |
1476 | pub fn parse_callbacks( |
1477 | mut self, |
1478 | cb: Box<dyn callbacks::ParseCallbacks>, |
1479 | ) -> Self { |
1480 | self.options.parse_callbacks.push(Rc::from(cb)); |
1481 | self |
1482 | } |
1483 | |
1484 | /// Choose what to generate using a |
1485 | /// [`CodegenConfig`](./struct.CodegenConfig.html). |
1486 | pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { |
1487 | self.options.codegen_config = config; |
1488 | self |
1489 | } |
1490 | |
1491 | /// Whether to detect include paths using clang_sys. |
1492 | pub fn detect_include_paths(mut self, doit: bool) -> Self { |
1493 | self.options.detect_include_paths = doit; |
1494 | self |
1495 | } |
1496 | |
1497 | /// Whether to try to fit macro constants to types smaller than u32/i32 |
1498 | pub fn fit_macro_constants(mut self, doit: bool) -> Self { |
1499 | self.options.fit_macro_constants = doit; |
1500 | self |
1501 | } |
1502 | |
1503 | /// Prepend the enum name to constant or newtype variants. |
1504 | pub fn prepend_enum_name(mut self, doit: bool) -> Self { |
1505 | self.options.prepend_enum_name = doit; |
1506 | self |
1507 | } |
1508 | |
1509 | /// Set whether `size_t` should be translated to `usize` automatically. |
1510 | pub fn size_t_is_usize(mut self, is: bool) -> Self { |
1511 | self.options.size_t_is_usize = is; |
1512 | self |
1513 | } |
1514 | |
1515 | /// Set whether rustfmt should format the generated bindings. |
1516 | pub fn rustfmt_bindings(mut self, doit: bool) -> Self { |
1517 | self.options.rustfmt_bindings = doit; |
1518 | self |
1519 | } |
1520 | |
1521 | /// Set whether we should record matched items in our regex sets. |
1522 | pub fn record_matches(mut self, doit: bool) -> Self { |
1523 | self.options.record_matches = doit; |
1524 | self |
1525 | } |
1526 | |
1527 | /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt |
1528 | /// options are used. |
1529 | pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self { |
1530 | self = self.rustfmt_bindings(true); |
1531 | self.options.rustfmt_configuration_file = path; |
1532 | self |
1533 | } |
1534 | |
1535 | /// Sets an explicit path to rustfmt, to be used when rustfmt is enabled. |
1536 | pub fn with_rustfmt<P: Into<PathBuf>>(mut self, path: P) -> Self { |
1537 | self.options.rustfmt_path = Some(path.into()); |
1538 | self |
1539 | } |
1540 | |
1541 | /// If true, always emit explicit padding fields. |
1542 | /// |
1543 | /// If a struct needs to be serialized in its native format (padding bytes |
1544 | /// and all), for example writing it to a file or sending it on the network, |
1545 | /// then this should be enabled, as anything reading the padding bytes of |
1546 | /// a struct may lead to Undefined Behavior. |
1547 | pub fn explicit_padding(mut self, doit: bool) -> Self { |
1548 | self.options.force_explicit_padding = doit; |
1549 | self |
1550 | } |
1551 | |
1552 | /// If true, enables experimental support to generate vtable functions. |
1553 | /// |
1554 | /// Should mostly work, though some edge cases are likely to be broken. |
1555 | pub fn vtable_generation(mut self, doit: bool) -> Self { |
1556 | self.options.vtable_generation = doit; |
1557 | self |
1558 | } |
1559 | |
1560 | /// If true, enables the sorting of the output in a predefined manner. |
1561 | /// |
1562 | /// TODO: Perhaps move the sorting order out into a config |
1563 | pub fn sort_semantically(mut self, doit: bool) -> Self { |
1564 | self.options.sort_semantically = doit; |
1565 | self |
1566 | } |
1567 | |
1568 | /// If true, merges extern blocks. |
1569 | pub fn merge_extern_blocks(mut self, doit: bool) -> Self { |
1570 | self.options.merge_extern_blocks = doit; |
1571 | self |
1572 | } |
1573 | |
1574 | /// Generate the Rust bindings using the options built up thus far. |
1575 | pub fn generate(mut self) -> Result<Bindings, BindgenError> { |
1576 | // Add any extra arguments from the environment to the clang command line. |
1577 | self.options.clang_args.extend(get_extra_clang_args()); |
1578 | |
1579 | // Transform input headers to arguments on the clang command line. |
1580 | self.options.clang_args.extend( |
1581 | self.options.input_headers |
1582 | [..self.options.input_headers.len().saturating_sub(1)] |
1583 | .iter() |
1584 | .flat_map(|header| ["-include" .into(), header.to_string()]), |
1585 | ); |
1586 | |
1587 | let input_unsaved_files = |
1588 | std::mem::take(&mut self.options.input_header_contents) |
1589 | .into_iter() |
1590 | .map(|(name, contents)| clang::UnsavedFile::new(name, contents)) |
1591 | .collect::<Vec<_>>(); |
1592 | |
1593 | Bindings::generate(self.options, input_unsaved_files) |
1594 | } |
1595 | |
1596 | /// Preprocess and dump the input header files to disk. |
1597 | /// |
1598 | /// This is useful when debugging bindgen, using C-Reduce, or when filing |
1599 | /// issues. The resulting file will be named something like `__bindgen.i` or |
1600 | /// `__bindgen.ii` |
1601 | pub fn dump_preprocessed_input(&self) -> io::Result<()> { |
1602 | let clang = |
1603 | clang_sys::support::Clang::find(None, &[]).ok_or_else(|| { |
1604 | io::Error::new( |
1605 | io::ErrorKind::Other, |
1606 | "Cannot find clang executable" , |
1607 | ) |
1608 | })?; |
1609 | |
1610 | // The contents of a wrapper file that includes all the input header |
1611 | // files. |
1612 | let mut wrapper_contents = String::new(); |
1613 | |
1614 | // Whether we are working with C or C++ inputs. |
1615 | let mut is_cpp = args_are_cpp(&self.options.clang_args); |
1616 | |
1617 | // For each input header, add `#include "$header"`. |
1618 | for header in &self.options.input_headers { |
1619 | is_cpp |= file_is_cpp(header); |
1620 | |
1621 | wrapper_contents.push_str("#include \"" ); |
1622 | wrapper_contents.push_str(header); |
1623 | wrapper_contents.push_str(" \"\n" ); |
1624 | } |
1625 | |
1626 | // For each input header content, add a prefix line of `#line 0 "$name"` |
1627 | // followed by the contents. |
1628 | for (name, contents) in &self.options.input_header_contents { |
1629 | is_cpp |= file_is_cpp(name); |
1630 | |
1631 | wrapper_contents.push_str("#line 0 \"" ); |
1632 | wrapper_contents.push_str(name); |
1633 | wrapper_contents.push_str(" \"\n" ); |
1634 | wrapper_contents.push_str(contents); |
1635 | } |
1636 | |
1637 | let wrapper_path = PathBuf::from(if is_cpp { |
1638 | "__bindgen.cpp" |
1639 | } else { |
1640 | "__bindgen.c" |
1641 | }); |
1642 | |
1643 | { |
1644 | let mut wrapper_file = File::create(&wrapper_path)?; |
1645 | wrapper_file.write_all(wrapper_contents.as_bytes())?; |
1646 | } |
1647 | |
1648 | let mut cmd = Command::new(clang.path); |
1649 | cmd.arg("-save-temps" ) |
1650 | .arg("-E" ) |
1651 | .arg("-C" ) |
1652 | .arg("-c" ) |
1653 | .arg(&wrapper_path) |
1654 | .stdout(Stdio::piped()); |
1655 | |
1656 | for a in &self.options.clang_args { |
1657 | cmd.arg(a); |
1658 | } |
1659 | |
1660 | for a in get_extra_clang_args() { |
1661 | cmd.arg(a); |
1662 | } |
1663 | |
1664 | let mut child = cmd.spawn()?; |
1665 | |
1666 | let mut preprocessed = child.stdout.take().unwrap(); |
1667 | let mut file = File::create(if is_cpp { |
1668 | "__bindgen.ii" |
1669 | } else { |
1670 | "__bindgen.i" |
1671 | })?; |
1672 | io::copy(&mut preprocessed, &mut file)?; |
1673 | |
1674 | if child.wait()?.success() { |
1675 | Ok(()) |
1676 | } else { |
1677 | Err(io::Error::new( |
1678 | io::ErrorKind::Other, |
1679 | "clang exited with non-zero status" , |
1680 | )) |
1681 | } |
1682 | } |
1683 | |
1684 | fn_with_regex_arg! { |
1685 | /// Don't derive `PartialEq` for a given type. Regular |
1686 | /// expressions are supported. |
1687 | pub fn no_partialeq<T: Into<String>>(mut self, arg: T) -> Builder { |
1688 | self.options.no_partialeq_types.insert(arg.into()); |
1689 | self |
1690 | } |
1691 | } |
1692 | |
1693 | fn_with_regex_arg! { |
1694 | /// Don't derive `Copy` for a given type. Regular |
1695 | /// expressions are supported. |
1696 | pub fn no_copy<T: Into<String>>(mut self, arg: T) -> Self { |
1697 | self.options.no_copy_types.insert(arg.into()); |
1698 | self |
1699 | } |
1700 | } |
1701 | |
1702 | fn_with_regex_arg! { |
1703 | /// Don't derive `Debug` for a given type. Regular |
1704 | /// expressions are supported. |
1705 | pub fn no_debug<T: Into<String>>(mut self, arg: T) -> Self { |
1706 | self.options.no_debug_types.insert(arg.into()); |
1707 | self |
1708 | } |
1709 | } |
1710 | |
1711 | fn_with_regex_arg! { |
1712 | /// Don't derive/impl `Default` for a given type. Regular |
1713 | /// expressions are supported. |
1714 | pub fn no_default<T: Into<String>>(mut self, arg: T) -> Self { |
1715 | self.options.no_default_types.insert(arg.into()); |
1716 | self |
1717 | } |
1718 | } |
1719 | |
1720 | fn_with_regex_arg! { |
1721 | /// Don't derive `Hash` for a given type. Regular |
1722 | /// expressions are supported. |
1723 | pub fn no_hash<T: Into<String>>(mut self, arg: T) -> Builder { |
1724 | self.options.no_hash_types.insert(arg.into()); |
1725 | self |
1726 | } |
1727 | } |
1728 | |
1729 | fn_with_regex_arg! { |
1730 | /// Add `#[must_use]` for the given type. Regular |
1731 | /// expressions are supported. |
1732 | pub fn must_use_type<T: Into<String>>(mut self, arg: T) -> Builder { |
1733 | self.options.must_use_types.insert(arg.into()); |
1734 | self |
1735 | } |
1736 | } |
1737 | |
1738 | /// Set whether `arr[size]` should be treated as `*mut T` or `*mut [T; size]` (same for mut) |
1739 | pub fn array_pointers_in_arguments(mut self, doit: bool) -> Self { |
1740 | self.options.array_pointers_in_arguments = doit; |
1741 | self |
1742 | } |
1743 | |
1744 | /// Set the wasm import module name |
1745 | pub fn wasm_import_module_name<T: Into<String>>( |
1746 | mut self, |
1747 | import_name: T, |
1748 | ) -> Self { |
1749 | self.options.wasm_import_module_name = Some(import_name.into()); |
1750 | self |
1751 | } |
1752 | |
1753 | /// Specify the dynamic library name if we are generating bindings for a shared library. |
1754 | pub fn dynamic_library_name<T: Into<String>>( |
1755 | mut self, |
1756 | dynamic_library_name: T, |
1757 | ) -> Self { |
1758 | self.options.dynamic_library_name = Some(dynamic_library_name.into()); |
1759 | self |
1760 | } |
1761 | |
1762 | /// Require successful linkage for all routines in a shared library. |
1763 | /// This allows us to optimize function calls by being able to safely assume function pointers |
1764 | /// are valid. |
1765 | pub fn dynamic_link_require_all(mut self, req: bool) -> Self { |
1766 | self.options.dynamic_link_require_all = req; |
1767 | self |
1768 | } |
1769 | |
1770 | /// Generate bindings as `pub` only if the bound item is publically accessible by C++. |
1771 | pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self { |
1772 | self.options.respect_cxx_access_specs = doit; |
1773 | self |
1774 | } |
1775 | |
1776 | /// Always translate enum integer types to native Rust integer types. |
1777 | /// |
1778 | /// This will result in enums having types such as `u32` and `i16` instead |
1779 | /// of `c_uint` and `c_short`. Types for Rustified enums are always |
1780 | /// translated. |
1781 | pub fn translate_enum_integer_types(mut self, doit: bool) -> Self { |
1782 | self.options.translate_enum_integer_types = doit; |
1783 | self |
1784 | } |
1785 | |
1786 | /// Generate types with C style naming. |
1787 | /// |
1788 | /// This will add prefixes to the generated type names. For example instead of a struct `A` we |
1789 | /// will generate struct `struct_A`. Currently applies to structs, unions, and enums. |
1790 | pub fn c_naming(mut self, doit: bool) -> Self { |
1791 | self.options.c_naming = doit; |
1792 | self |
1793 | } |
1794 | |
1795 | /// Override the ABI of a given function. Regular expressions are supported. |
1796 | pub fn override_abi<T: Into<String>>(mut self, abi: Abi, arg: T) -> Self { |
1797 | self.options |
1798 | .abi_overrides |
1799 | .entry(abi) |
1800 | .or_default() |
1801 | .insert(arg.into()); |
1802 | self |
1803 | } |
1804 | |
1805 | /// If true, wraps unsafe operations in unsafe blocks. |
1806 | pub fn wrap_unsafe_ops(mut self, doit: bool) -> Self { |
1807 | self.options.wrap_unsafe_ops = doit; |
1808 | self |
1809 | } |
1810 | |
1811 | #[cfg (feature = "experimental" )] |
1812 | /// Whether to generate extern wrappers for `static` and `static inline` functions. Defaults to |
1813 | /// false. |
1814 | pub fn wrap_static_fns(mut self, doit: bool) -> Self { |
1815 | self.options.wrap_static_fns = doit; |
1816 | self |
1817 | } |
1818 | |
1819 | #[cfg (feature = "experimental" )] |
1820 | /// Set the path for the source code file that would be created if any wrapper functions must |
1821 | /// be generated due to the presence of static functions. |
1822 | /// |
1823 | /// Bindgen will automatically add the right extension to the header and source code files. |
1824 | pub fn wrap_static_fns_path<T: AsRef<Path>>(mut self, path: T) -> Self { |
1825 | self.options.wrap_static_fns_path = Some(path.as_ref().to_owned()); |
1826 | self |
1827 | } |
1828 | |
1829 | #[cfg (feature = "experimental" )] |
1830 | /// Set the suffix added to the extern wrapper functions generated for `static` and `static |
1831 | /// inline` functions. |
1832 | pub fn wrap_static_fns_suffix<T: AsRef<str>>(mut self, suffix: T) -> Self { |
1833 | self.options.wrap_static_fns_suffix = Some(suffix.as_ref().to_owned()); |
1834 | self |
1835 | } |
1836 | } |
1837 | |
1838 | /// Configuration options for generated bindings. |
1839 | #[derive (Clone, Debug)] |
1840 | struct BindgenOptions { |
1841 | /// The set of types that have been blocklisted and should not appear |
1842 | /// anywhere in the generated code. |
1843 | blocklisted_types: RegexSet, |
1844 | |
1845 | /// The set of functions that have been blocklisted and should not appear |
1846 | /// in the generated code. |
1847 | blocklisted_functions: RegexSet, |
1848 | |
1849 | /// The set of items, regardless of item-type, that have been |
1850 | /// blocklisted and should not appear in the generated code. |
1851 | blocklisted_items: RegexSet, |
1852 | |
1853 | /// The set of files whose contents should be blocklisted and should not |
1854 | /// appear in the generated code. |
1855 | blocklisted_files: RegexSet, |
1856 | |
1857 | /// The set of types that should be treated as opaque structures in the |
1858 | /// generated code. |
1859 | opaque_types: RegexSet, |
1860 | |
1861 | /// The explicit rustfmt path. |
1862 | rustfmt_path: Option<PathBuf>, |
1863 | |
1864 | /// The path to which we should write a Makefile-syntax depfile (if any). |
1865 | depfile: Option<deps::DepfileSpec>, |
1866 | |
1867 | /// The set of types that we should have bindings for in the generated |
1868 | /// code. |
1869 | /// |
1870 | /// This includes all types transitively reachable from any type in this |
1871 | /// set. One might think of allowlisted types/vars/functions as GC roots, |
1872 | /// and the generated Rust code as including everything that gets marked. |
1873 | allowlisted_types: RegexSet, |
1874 | |
1875 | /// Allowlisted functions. See docs for `allowlisted_types` for more. |
1876 | allowlisted_functions: RegexSet, |
1877 | |
1878 | /// Allowlisted variables. See docs for `allowlisted_types` for more. |
1879 | allowlisted_vars: RegexSet, |
1880 | |
1881 | /// The set of files whose contents should be allowlisted. |
1882 | allowlisted_files: RegexSet, |
1883 | |
1884 | /// The default style of code to generate for enums |
1885 | default_enum_style: codegen::EnumVariation, |
1886 | |
1887 | /// The enum patterns to mark an enum as a bitfield |
1888 | /// (newtype with bitwise operations). |
1889 | bitfield_enums: RegexSet, |
1890 | |
1891 | /// The enum patterns to mark an enum as a newtype. |
1892 | newtype_enums: RegexSet, |
1893 | |
1894 | /// The enum patterns to mark an enum as a global newtype. |
1895 | newtype_global_enums: RegexSet, |
1896 | |
1897 | /// The enum patterns to mark an enum as a Rust enum. |
1898 | rustified_enums: RegexSet, |
1899 | |
1900 | /// The enum patterns to mark an enum as a non-exhaustive Rust enum. |
1901 | rustified_non_exhaustive_enums: RegexSet, |
1902 | |
1903 | /// The enum patterns to mark an enum as a module of constants. |
1904 | constified_enum_modules: RegexSet, |
1905 | |
1906 | /// The enum patterns to mark an enum as a set of constants. |
1907 | constified_enums: RegexSet, |
1908 | |
1909 | /// The default type for C macro constants. |
1910 | default_macro_constant_type: codegen::MacroTypeVariation, |
1911 | |
1912 | /// The default style of code to generate for typedefs. |
1913 | default_alias_style: codegen::AliasVariation, |
1914 | |
1915 | /// Typedef patterns that will use regular type aliasing. |
1916 | type_alias: RegexSet, |
1917 | |
1918 | /// Typedef patterns that will be aliased by creating a new struct. |
1919 | new_type_alias: RegexSet, |
1920 | |
1921 | /// Typedef patterns that will be wrapped in a new struct and have |
1922 | /// Deref and Deref to their aliased type. |
1923 | new_type_alias_deref: RegexSet, |
1924 | |
1925 | /// The default style of code to generate for union containing non-Copy |
1926 | /// members. |
1927 | default_non_copy_union_style: codegen::NonCopyUnionStyle, |
1928 | |
1929 | /// The union patterns to mark an non-Copy union as using the bindgen |
1930 | /// generated wrapper. |
1931 | bindgen_wrapper_union: RegexSet, |
1932 | |
1933 | /// The union patterns to mark an non-Copy union as using the |
1934 | /// `::core::mem::ManuallyDrop` wrapper. |
1935 | manually_drop_union: RegexSet, |
1936 | |
1937 | /// Whether we should generate builtins or not. |
1938 | builtins: bool, |
1939 | |
1940 | /// True if we should dump the Clang AST for debugging purposes. |
1941 | emit_ast: bool, |
1942 | |
1943 | /// True if we should dump our internal IR for debugging purposes. |
1944 | emit_ir: bool, |
1945 | |
1946 | /// Output graphviz dot file. |
1947 | emit_ir_graphviz: Option<String>, |
1948 | |
1949 | /// True if we should emulate C++ namespaces with Rust modules in the |
1950 | /// generated bindings. |
1951 | enable_cxx_namespaces: bool, |
1952 | |
1953 | /// True if we should try to find unexposed attributes in functions, in |
1954 | /// order to be able to generate #[must_use] attributes in Rust. |
1955 | enable_function_attribute_detection: bool, |
1956 | |
1957 | /// True if we should avoid mangling names with namespaces. |
1958 | disable_name_namespacing: bool, |
1959 | |
1960 | /// True if we should avoid generating nested struct names. |
1961 | disable_nested_struct_naming: bool, |
1962 | |
1963 | /// True if we should avoid embedding version identifiers into source code. |
1964 | disable_header_comment: bool, |
1965 | |
1966 | /// True if we should generate layout tests for generated structures. |
1967 | layout_tests: bool, |
1968 | |
1969 | /// True if we should implement the Debug trait for C/C++ structures and types |
1970 | /// that do not support automatically deriving Debug. |
1971 | impl_debug: bool, |
1972 | |
1973 | /// True if we should implement the PartialEq trait for C/C++ structures and types |
1974 | /// that do not support automatically deriving PartialEq. |
1975 | impl_partialeq: bool, |
1976 | |
1977 | /// True if we should derive Copy trait implementations for C/C++ structures |
1978 | /// and types. |
1979 | derive_copy: bool, |
1980 | |
1981 | /// True if we should derive Debug trait implementations for C/C++ structures |
1982 | /// and types. |
1983 | derive_debug: bool, |
1984 | |
1985 | /// True if we should derive Default trait implementations for C/C++ structures |
1986 | /// and types. |
1987 | derive_default: bool, |
1988 | |
1989 | /// True if we should derive Hash trait implementations for C/C++ structures |
1990 | /// and types. |
1991 | derive_hash: bool, |
1992 | |
1993 | /// True if we should derive PartialOrd trait implementations for C/C++ structures |
1994 | /// and types. |
1995 | derive_partialord: bool, |
1996 | |
1997 | /// True if we should derive Ord trait implementations for C/C++ structures |
1998 | /// and types. |
1999 | derive_ord: bool, |
2000 | |
2001 | /// True if we should derive PartialEq trait implementations for C/C++ structures |
2002 | /// and types. |
2003 | derive_partialeq: bool, |
2004 | |
2005 | /// True if we should derive Eq trait implementations for C/C++ structures |
2006 | /// and types. |
2007 | derive_eq: bool, |
2008 | |
2009 | /// True if we should avoid using libstd to use libcore instead. |
2010 | use_core: bool, |
2011 | |
2012 | /// An optional prefix for the "raw" types, like `c_int`, `c_void`... |
2013 | ctypes_prefix: Option<String>, |
2014 | |
2015 | /// The prefix for the anon fields. |
2016 | anon_fields_prefix: String, |
2017 | |
2018 | /// Whether to time the bindgen phases. |
2019 | time_phases: bool, |
2020 | |
2021 | /// Whether we should convert float types to f32/f64 types. |
2022 | convert_floats: bool, |
2023 | |
2024 | /// The set of raw lines to prepend to the top-level module of generated |
2025 | /// Rust code. |
2026 | raw_lines: Vec<String>, |
2027 | |
2028 | /// The set of raw lines to prepend to each of the modules. |
2029 | /// |
2030 | /// This only makes sense if the `enable_cxx_namespaces` option is set. |
2031 | module_lines: HashMap<String, Vec<String>>, |
2032 | |
2033 | /// The set of arguments to pass straight through to Clang. |
2034 | clang_args: Vec<String>, |
2035 | |
2036 | /// The input header files. |
2037 | input_headers: Vec<String>, |
2038 | |
2039 | /// Tuples of unsaved file contents of the form (name, contents). |
2040 | input_header_contents: Vec<(String, String)>, |
2041 | |
2042 | /// A user-provided visitor to allow customizing different kinds of |
2043 | /// situations. |
2044 | parse_callbacks: Vec<Rc<dyn callbacks::ParseCallbacks>>, |
2045 | |
2046 | /// Which kind of items should we generate? By default, we'll generate all |
2047 | /// of them. |
2048 | codegen_config: CodegenConfig, |
2049 | |
2050 | /// Whether to treat inline namespaces conservatively. |
2051 | /// |
2052 | /// See the builder method description for more details. |
2053 | conservative_inline_namespaces: bool, |
2054 | |
2055 | /// Whether to keep documentation comments in the generated output. See the |
2056 | /// documentation for more details. Defaults to true. |
2057 | generate_comments: bool, |
2058 | |
2059 | /// Whether to generate inline functions. Defaults to false. |
2060 | generate_inline_functions: bool, |
2061 | |
2062 | /// Whether to allowlist types recursively. Defaults to true. |
2063 | allowlist_recursively: bool, |
2064 | |
2065 | /// Instead of emitting 'use objc;' to files generated from objective c files, |
2066 | /// generate '#[macro_use] extern crate objc;' |
2067 | objc_extern_crate: bool, |
2068 | |
2069 | /// Instead of emitting 'use block;' to files generated from objective c files, |
2070 | /// generate '#[macro_use] extern crate block;' |
2071 | generate_block: bool, |
2072 | |
2073 | /// Instead of emitting 'use block;' to files generated from objective c files, |
2074 | /// generate '#[macro_use] extern crate block;' |
2075 | block_extern_crate: bool, |
2076 | |
2077 | /// Whether to use the clang-provided name mangling. This is true and |
2078 | /// probably needed for C++ features. |
2079 | /// |
2080 | /// However, some old libclang versions seem to return incorrect results in |
2081 | /// some cases for non-mangled functions, see [1], so we allow disabling it. |
2082 | /// |
2083 | /// [1]: https://github.com/rust-lang/rust-bindgen/issues/528 |
2084 | enable_mangling: bool, |
2085 | |
2086 | /// Whether to detect include paths using clang_sys. |
2087 | detect_include_paths: bool, |
2088 | |
2089 | /// Whether to try to fit macro constants into types smaller than u32/i32 |
2090 | fit_macro_constants: bool, |
2091 | |
2092 | /// Whether to prepend the enum name to constant or newtype variants. |
2093 | prepend_enum_name: bool, |
2094 | |
2095 | /// Version of the Rust compiler to target |
2096 | rust_target: RustTarget, |
2097 | |
2098 | /// Features to enable, derived from `rust_target` |
2099 | rust_features: RustFeatures, |
2100 | |
2101 | /// Whether we should record which items in the regex sets ever matched. |
2102 | /// |
2103 | /// This may be a bit slower, but will enable reporting of unused allowlist |
2104 | /// items via the `error!` log. |
2105 | record_matches: bool, |
2106 | |
2107 | /// Whether `size_t` should be translated to `usize` automatically. |
2108 | size_t_is_usize: bool, |
2109 | |
2110 | /// Whether rustfmt should format the generated bindings. |
2111 | rustfmt_bindings: bool, |
2112 | |
2113 | /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt |
2114 | /// options are used. |
2115 | rustfmt_configuration_file: Option<PathBuf>, |
2116 | |
2117 | /// The set of types that we should not derive `PartialEq` for. |
2118 | no_partialeq_types: RegexSet, |
2119 | |
2120 | /// The set of types that we should not derive `Copy` for. |
2121 | no_copy_types: RegexSet, |
2122 | |
2123 | /// The set of types that we should not derive `Debug` for. |
2124 | no_debug_types: RegexSet, |
2125 | |
2126 | /// The set of types that we should not derive/impl `Default` for. |
2127 | no_default_types: RegexSet, |
2128 | |
2129 | /// The set of types that we should not derive `Hash` for. |
2130 | no_hash_types: RegexSet, |
2131 | |
2132 | /// The set of types that we should be annotated with `#[must_use]`. |
2133 | must_use_types: RegexSet, |
2134 | |
2135 | /// Decide if C arrays should be regular pointers in rust or array pointers |
2136 | array_pointers_in_arguments: bool, |
2137 | |
2138 | /// Wasm import module name. |
2139 | wasm_import_module_name: Option<String>, |
2140 | |
2141 | /// The name of the dynamic library (if we are generating bindings for a shared library). If |
2142 | /// this is None, no dynamic bindings are created. |
2143 | dynamic_library_name: Option<String>, |
2144 | |
2145 | /// Require successful linkage for all routines in a shared library. |
2146 | /// This allows us to optimize function calls by being able to safely assume function pointers |
2147 | /// are valid. No effect if `dynamic_library_name` is None. |
2148 | dynamic_link_require_all: bool, |
2149 | |
2150 | /// Only make generated bindings `pub` if the items would be publically accessible |
2151 | /// by C++. |
2152 | respect_cxx_access_specs: bool, |
2153 | |
2154 | /// Always translate enum integer types to native Rust integer types. |
2155 | translate_enum_integer_types: bool, |
2156 | |
2157 | /// Generate types with C style naming. |
2158 | c_naming: bool, |
2159 | |
2160 | /// Always output explicit padding fields |
2161 | force_explicit_padding: bool, |
2162 | |
2163 | /// Emit vtable functions. |
2164 | vtable_generation: bool, |
2165 | |
2166 | /// Sort the code generation. |
2167 | sort_semantically: bool, |
2168 | |
2169 | /// Deduplicate `extern` blocks. |
2170 | merge_extern_blocks: bool, |
2171 | |
2172 | abi_overrides: HashMap<Abi, RegexSet>, |
2173 | |
2174 | /// Whether to wrap unsafe operations in unsafe blocks or not. |
2175 | wrap_unsafe_ops: bool, |
2176 | |
2177 | wrap_static_fns: bool, |
2178 | |
2179 | wrap_static_fns_suffix: Option<String>, |
2180 | |
2181 | wrap_static_fns_path: Option<PathBuf>, |
2182 | } |
2183 | |
2184 | impl BindgenOptions { |
2185 | fn build(&mut self) { |
2186 | let regex_sets = [ |
2187 | &mut self.allowlisted_vars, |
2188 | &mut self.allowlisted_types, |
2189 | &mut self.allowlisted_functions, |
2190 | &mut self.allowlisted_files, |
2191 | &mut self.blocklisted_types, |
2192 | &mut self.blocklisted_functions, |
2193 | &mut self.blocklisted_items, |
2194 | &mut self.blocklisted_files, |
2195 | &mut self.opaque_types, |
2196 | &mut self.bitfield_enums, |
2197 | &mut self.constified_enums, |
2198 | &mut self.constified_enum_modules, |
2199 | &mut self.newtype_enums, |
2200 | &mut self.newtype_global_enums, |
2201 | &mut self.rustified_enums, |
2202 | &mut self.rustified_non_exhaustive_enums, |
2203 | &mut self.type_alias, |
2204 | &mut self.new_type_alias, |
2205 | &mut self.new_type_alias_deref, |
2206 | &mut self.bindgen_wrapper_union, |
2207 | &mut self.manually_drop_union, |
2208 | &mut self.no_partialeq_types, |
2209 | &mut self.no_copy_types, |
2210 | &mut self.no_debug_types, |
2211 | &mut self.no_default_types, |
2212 | &mut self.no_hash_types, |
2213 | &mut self.must_use_types, |
2214 | ]; |
2215 | let record_matches = self.record_matches; |
2216 | for regex_set in self.abi_overrides.values_mut().chain(regex_sets) { |
2217 | regex_set.build(record_matches); |
2218 | } |
2219 | } |
2220 | |
2221 | /// Update rust target version |
2222 | pub fn set_rust_target(&mut self, rust_target: RustTarget) { |
2223 | self.rust_target = rust_target; |
2224 | |
2225 | // Keep rust_features synced with rust_target |
2226 | self.rust_features = rust_target.into(); |
2227 | } |
2228 | |
2229 | /// Get features supported by target Rust version |
2230 | pub fn rust_features(&self) -> RustFeatures { |
2231 | self.rust_features |
2232 | } |
2233 | |
2234 | fn last_callback<T>( |
2235 | &self, |
2236 | f: impl Fn(&dyn callbacks::ParseCallbacks) -> Option<T>, |
2237 | ) -> Option<T> { |
2238 | self.parse_callbacks |
2239 | .iter() |
2240 | .filter_map(|cb| f(cb.as_ref())) |
2241 | .last() |
2242 | } |
2243 | |
2244 | fn all_callbacks<T>( |
2245 | &self, |
2246 | f: impl Fn(&dyn callbacks::ParseCallbacks) -> Vec<T>, |
2247 | ) -> Vec<T> { |
2248 | self.parse_callbacks |
2249 | .iter() |
2250 | .flat_map(|cb| f(cb.as_ref())) |
2251 | .collect() |
2252 | } |
2253 | |
2254 | fn process_comment(&self, comment: &str) -> String { |
2255 | let comment = comment::preprocess(comment); |
2256 | self.parse_callbacks |
2257 | .last() |
2258 | .and_then(|cb| cb.process_comment(&comment)) |
2259 | .unwrap_or(comment) |
2260 | } |
2261 | } |
2262 | |
2263 | impl Default for BindgenOptions { |
2264 | fn default() -> BindgenOptions { |
2265 | macro_rules! options { |
2266 | ($($field:ident $(: $value:expr)?,)* --default-fields-- $($default_field:ident,)*) => { |
2267 | BindgenOptions { |
2268 | $($field $(: $value)*,)* |
2269 | $($default_field: Default::default(),)* |
2270 | } |
2271 | }; |
2272 | } |
2273 | |
2274 | let rust_target = RustTarget::default(); |
2275 | |
2276 | options! { |
2277 | rust_target, |
2278 | rust_features: rust_target.into(), |
2279 | layout_tests: true, |
2280 | derive_copy: true, |
2281 | derive_debug: true, |
2282 | anon_fields_prefix: DEFAULT_ANON_FIELDS_PREFIX.into(), |
2283 | convert_floats: true, |
2284 | codegen_config: CodegenConfig::all(), |
2285 | generate_comments: true, |
2286 | allowlist_recursively: true, |
2287 | enable_mangling: true, |
2288 | detect_include_paths: true, |
2289 | prepend_enum_name: true, |
2290 | record_matches: true, |
2291 | rustfmt_bindings: true, |
2292 | size_t_is_usize: true, |
2293 | |
2294 | --default-fields-- |
2295 | blocklisted_types, |
2296 | blocklisted_functions, |
2297 | blocklisted_items, |
2298 | blocklisted_files, |
2299 | opaque_types, |
2300 | rustfmt_path, |
2301 | depfile, |
2302 | allowlisted_types, |
2303 | allowlisted_functions, |
2304 | allowlisted_vars, |
2305 | allowlisted_files, |
2306 | default_enum_style, |
2307 | bitfield_enums, |
2308 | newtype_enums, |
2309 | newtype_global_enums, |
2310 | rustified_enums, |
2311 | rustified_non_exhaustive_enums, |
2312 | constified_enums, |
2313 | constified_enum_modules, |
2314 | default_macro_constant_type, |
2315 | default_alias_style, |
2316 | type_alias, |
2317 | new_type_alias, |
2318 | new_type_alias_deref, |
2319 | default_non_copy_union_style, |
2320 | bindgen_wrapper_union, |
2321 | manually_drop_union, |
2322 | builtins, |
2323 | emit_ast, |
2324 | emit_ir, |
2325 | emit_ir_graphviz, |
2326 | impl_debug, |
2327 | impl_partialeq, |
2328 | derive_default, |
2329 | derive_hash, |
2330 | derive_partialord, |
2331 | derive_ord, |
2332 | derive_partialeq, |
2333 | derive_eq, |
2334 | enable_cxx_namespaces, |
2335 | enable_function_attribute_detection, |
2336 | disable_name_namespacing, |
2337 | disable_nested_struct_naming, |
2338 | disable_header_comment, |
2339 | use_core, |
2340 | ctypes_prefix, |
2341 | raw_lines, |
2342 | module_lines, |
2343 | clang_args, |
2344 | input_headers, |
2345 | input_header_contents, |
2346 | parse_callbacks, |
2347 | conservative_inline_namespaces, |
2348 | generate_inline_functions, |
2349 | generate_block, |
2350 | objc_extern_crate, |
2351 | block_extern_crate, |
2352 | fit_macro_constants, |
2353 | time_phases, |
2354 | rustfmt_configuration_file, |
2355 | no_partialeq_types, |
2356 | no_copy_types, |
2357 | no_debug_types, |
2358 | no_default_types, |
2359 | no_hash_types, |
2360 | must_use_types, |
2361 | array_pointers_in_arguments, |
2362 | wasm_import_module_name, |
2363 | dynamic_library_name, |
2364 | dynamic_link_require_all, |
2365 | respect_cxx_access_specs, |
2366 | translate_enum_integer_types, |
2367 | c_naming, |
2368 | force_explicit_padding, |
2369 | vtable_generation, |
2370 | sort_semantically, |
2371 | merge_extern_blocks, |
2372 | abi_overrides, |
2373 | wrap_unsafe_ops, |
2374 | wrap_static_fns, |
2375 | wrap_static_fns_suffix, |
2376 | wrap_static_fns_path, |
2377 | } |
2378 | } |
2379 | } |
2380 | |
2381 | #[cfg (feature = "runtime" )] |
2382 | fn ensure_libclang_is_loaded() { |
2383 | if clang_sys::is_loaded() { |
2384 | return; |
2385 | } |
2386 | |
2387 | // XXX (issue #350): Ensure that our dynamically loaded `libclang` |
2388 | // doesn't get dropped prematurely, nor is loaded multiple times |
2389 | // across different threads. |
2390 | |
2391 | lazy_static! { |
2392 | static ref LIBCLANG: std::sync::Arc<clang_sys::SharedLibrary> = { |
2393 | clang_sys::load().expect("Unable to find libclang" ); |
2394 | clang_sys::get_library().expect( |
2395 | "We just loaded libclang and it had better still be \ |
2396 | here!" , |
2397 | ) |
2398 | }; |
2399 | } |
2400 | |
2401 | clang_sys::set_library(Some(LIBCLANG.clone())); |
2402 | } |
2403 | |
2404 | #[cfg (not(feature = "runtime" ))] |
2405 | fn ensure_libclang_is_loaded() {} |
2406 | |
2407 | /// Error type for rust-bindgen. |
2408 | #[derive (Debug, Clone, PartialEq, Eq, Hash)] |
2409 | #[non_exhaustive ] |
2410 | pub enum BindgenError { |
2411 | /// The header was a folder. |
2412 | FolderAsHeader(PathBuf), |
2413 | /// Permissions to read the header is insufficient. |
2414 | InsufficientPermissions(PathBuf), |
2415 | /// The header does not exist. |
2416 | NotExist(PathBuf), |
2417 | /// Clang diagnosed an error. |
2418 | ClangDiagnostic(String), |
2419 | /// Code generation reported an error. |
2420 | Codegen(CodegenError), |
2421 | } |
2422 | |
2423 | impl std::fmt::Display for BindgenError { |
2424 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
2425 | match self { |
2426 | BindgenError::FolderAsHeader(h: &PathBuf) => { |
2427 | write!(f, "' {}' is a folder" , h.display()) |
2428 | } |
2429 | BindgenError::InsufficientPermissions(h: &PathBuf) => { |
2430 | write!(f, "insufficient permissions to read ' {}'" , h.display()) |
2431 | } |
2432 | BindgenError::NotExist(h: &PathBuf) => { |
2433 | write!(f, "header ' {}' does not exist." , h.display()) |
2434 | } |
2435 | BindgenError::ClangDiagnostic(message: &String) => { |
2436 | write!(f, "clang diagnosed error: {}" , message) |
2437 | } |
2438 | BindgenError::Codegen(err: &CodegenError) => { |
2439 | write!(f, "codegen error: {}" , err) |
2440 | } |
2441 | } |
2442 | } |
2443 | } |
2444 | |
2445 | impl std::error::Error for BindgenError {} |
2446 | |
2447 | /// Generated Rust bindings. |
2448 | #[derive (Debug)] |
2449 | pub struct Bindings { |
2450 | options: BindgenOptions, |
2451 | warnings: Vec<String>, |
2452 | module: proc_macro2::TokenStream, |
2453 | } |
2454 | |
2455 | pub(crate) const HOST_TARGET: &str = |
2456 | include_str!(concat!(env!("OUT_DIR" ), "/host-target.txt" )); |
2457 | |
2458 | // Some architecture triplets are different between rust and libclang, see #1211 |
2459 | // and duplicates. |
2460 | fn rust_to_clang_target(rust_target: &str) -> String { |
2461 | if rust_target.starts_with("aarch64-apple-" ) { |
2462 | let mut clang_target: String = "arm64-apple-" .to_owned(); |
2463 | clang_target |
2464 | .push_str(string:rust_target.strip_prefix("aarch64-apple-" ).unwrap()); |
2465 | return clang_target; |
2466 | } else if rust_target.starts_with("riscv64gc-" ) { |
2467 | let mut clang_target: String = "riscv64-" .to_owned(); |
2468 | clang_target.push_str(string:rust_target.strip_prefix("riscv64gc-" ).unwrap()); |
2469 | return clang_target; |
2470 | } else if rust_target.ends_with("-espidf" ) { |
2471 | let mut clang_target: String = |
2472 | rust_target.strip_suffix("-espidf" ).unwrap().to_owned(); |
2473 | clang_target.push_str(string:"-elf" ); |
2474 | if clang_target.starts_with("riscv32imc-" ) { |
2475 | clang_target = "riscv32-" .to_owned() + |
2476 | clang_target.strip_prefix("riscv32imc-" ).unwrap(); |
2477 | } |
2478 | return clang_target; |
2479 | } |
2480 | rust_target.to_owned() |
2481 | } |
2482 | |
2483 | /// Returns the effective target, and whether it was explicitly specified on the |
2484 | /// clang flags. |
2485 | fn find_effective_target(clang_args: &[String]) -> (String, bool) { |
2486 | let mut args: Iter<'_, String> = clang_args.iter(); |
2487 | while let Some(opt: &String) = args.next() { |
2488 | if opt.starts_with("--target=" ) { |
2489 | let mut split: Split<'_, char> = opt.split('=' ); |
2490 | split.next(); |
2491 | return (split.next().unwrap().to_owned(), true); |
2492 | } |
2493 | |
2494 | if opt == "-target" { |
2495 | if let Some(target: &String) = args.next() { |
2496 | return (target.clone(), true); |
2497 | } |
2498 | } |
2499 | } |
2500 | |
2501 | // If we're running from a build script, try to find the cargo target. |
2502 | if let Ok(t: String) = env::var(key:"TARGET" ) { |
2503 | return (rust_to_clang_target(&t), false); |
2504 | } |
2505 | |
2506 | (rust_to_clang_target(HOST_TARGET), false) |
2507 | } |
2508 | |
2509 | impl Bindings { |
2510 | /// Generate bindings for the given options. |
2511 | pub(crate) fn generate( |
2512 | mut options: BindgenOptions, |
2513 | input_unsaved_files: Vec<clang::UnsavedFile>, |
2514 | ) -> Result<Bindings, BindgenError> { |
2515 | ensure_libclang_is_loaded(); |
2516 | |
2517 | #[cfg (feature = "runtime" )] |
2518 | debug!( |
2519 | "Generating bindings, libclang at {}" , |
2520 | clang_sys::get_library().unwrap().path().display() |
2521 | ); |
2522 | #[cfg (not(feature = "runtime" ))] |
2523 | debug!("Generating bindings, libclang linked" ); |
2524 | |
2525 | options.build(); |
2526 | |
2527 | let (effective_target, explicit_target) = |
2528 | find_effective_target(&options.clang_args); |
2529 | |
2530 | let is_host_build = |
2531 | rust_to_clang_target(HOST_TARGET) == effective_target; |
2532 | |
2533 | // NOTE: The is_host_build check wouldn't be sound normally in some |
2534 | // cases if we were to call a binary (if you have a 32-bit clang and are |
2535 | // building on a 64-bit system for example). But since we rely on |
2536 | // opening libclang.so, it has to be the same architecture and thus the |
2537 | // check is fine. |
2538 | if !explicit_target && !is_host_build { |
2539 | options |
2540 | .clang_args |
2541 | .insert(0, format!("--target= {}" , effective_target)); |
2542 | }; |
2543 | |
2544 | fn detect_include_paths(options: &mut BindgenOptions) { |
2545 | if !options.detect_include_paths { |
2546 | return; |
2547 | } |
2548 | |
2549 | // Filter out include paths and similar stuff, so we don't incorrectly |
2550 | // promote them to `-isystem`. |
2551 | let clang_args_for_clang_sys = { |
2552 | let mut last_was_include_prefix = false; |
2553 | options |
2554 | .clang_args |
2555 | .iter() |
2556 | .filter(|arg| { |
2557 | if last_was_include_prefix { |
2558 | last_was_include_prefix = false; |
2559 | return false; |
2560 | } |
2561 | |
2562 | let arg = &**arg; |
2563 | |
2564 | // https://clang.llvm.org/docs/ClangCommandLineReference.html |
2565 | // -isystem and -isystem-after are harmless. |
2566 | if arg == "-I" || arg == "--include-directory" { |
2567 | last_was_include_prefix = true; |
2568 | return false; |
2569 | } |
2570 | |
2571 | if arg.starts_with("-I" ) || |
2572 | arg.starts_with("--include-directory=" ) |
2573 | { |
2574 | return false; |
2575 | } |
2576 | |
2577 | true |
2578 | }) |
2579 | .cloned() |
2580 | .collect::<Vec<_>>() |
2581 | }; |
2582 | |
2583 | debug!( |
2584 | "Trying to find clang with flags: {:?}" , |
2585 | clang_args_for_clang_sys |
2586 | ); |
2587 | |
2588 | let clang = match clang_sys::support::Clang::find( |
2589 | None, |
2590 | &clang_args_for_clang_sys, |
2591 | ) { |
2592 | None => return, |
2593 | Some(clang) => clang, |
2594 | }; |
2595 | |
2596 | debug!("Found clang: {:?}" , clang); |
2597 | |
2598 | // Whether we are working with C or C++ inputs. |
2599 | let is_cpp = args_are_cpp(&options.clang_args) || |
2600 | options.input_headers.iter().any(|h| file_is_cpp(h)); |
2601 | |
2602 | let search_paths = if is_cpp { |
2603 | clang.cpp_search_paths |
2604 | } else { |
2605 | clang.c_search_paths |
2606 | }; |
2607 | |
2608 | if let Some(search_paths) = search_paths { |
2609 | for path in search_paths.into_iter() { |
2610 | if let Ok(path) = path.into_os_string().into_string() { |
2611 | options.clang_args.push("-isystem" .to_owned()); |
2612 | options.clang_args.push(path); |
2613 | } |
2614 | } |
2615 | } |
2616 | } |
2617 | |
2618 | detect_include_paths(&mut options); |
2619 | |
2620 | #[cfg (unix)] |
2621 | fn can_read(perms: &std::fs::Permissions) -> bool { |
2622 | use std::os::unix::fs::PermissionsExt; |
2623 | perms.mode() & 0o444 > 0 |
2624 | } |
2625 | |
2626 | #[cfg (not(unix))] |
2627 | fn can_read(_: &std::fs::Permissions) -> bool { |
2628 | true |
2629 | } |
2630 | |
2631 | if let Some(h) = options.input_headers.last() { |
2632 | let path = Path::new(h); |
2633 | if let Ok(md) = std::fs::metadata(path) { |
2634 | if md.is_dir() { |
2635 | return Err(BindgenError::FolderAsHeader(path.into())); |
2636 | } |
2637 | if !can_read(&md.permissions()) { |
2638 | return Err(BindgenError::InsufficientPermissions( |
2639 | path.into(), |
2640 | )); |
2641 | } |
2642 | let h = h.clone(); |
2643 | options.clang_args.push(h); |
2644 | } else { |
2645 | return Err(BindgenError::NotExist(path.into())); |
2646 | } |
2647 | } |
2648 | |
2649 | for (idx, f) in input_unsaved_files.iter().enumerate() { |
2650 | if idx != 0 || !options.input_headers.is_empty() { |
2651 | options.clang_args.push("-include" .to_owned()); |
2652 | } |
2653 | options.clang_args.push(f.name.to_str().unwrap().to_owned()) |
2654 | } |
2655 | |
2656 | debug!("Fixed-up options: {:?}" , options); |
2657 | |
2658 | let time_phases = options.time_phases; |
2659 | let mut context = BindgenContext::new(options, &input_unsaved_files); |
2660 | |
2661 | if is_host_build { |
2662 | debug_assert_eq!( |
2663 | context.target_pointer_size(), |
2664 | std::mem::size_of::<*mut ()>(), |
2665 | " {:?} {:?}" , |
2666 | effective_target, |
2667 | HOST_TARGET |
2668 | ); |
2669 | } |
2670 | |
2671 | { |
2672 | let _t = time::Timer::new("parse" ).with_output(time_phases); |
2673 | parse(&mut context)?; |
2674 | } |
2675 | |
2676 | let (module, options, warnings) = |
2677 | codegen::codegen(context).map_err(BindgenError::Codegen)?; |
2678 | |
2679 | Ok(Bindings { |
2680 | options, |
2681 | warnings, |
2682 | module, |
2683 | }) |
2684 | } |
2685 | |
2686 | /// Write these bindings as source text to a file. |
2687 | pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { |
2688 | let file = OpenOptions::new() |
2689 | .write(true) |
2690 | .truncate(true) |
2691 | .create(true) |
2692 | .open(path.as_ref())?; |
2693 | self.write(Box::new(file))?; |
2694 | Ok(()) |
2695 | } |
2696 | |
2697 | /// Write these bindings as source text to the given `Write`able. |
2698 | pub fn write<'a>(&self, mut writer: Box<dyn Write + 'a>) -> io::Result<()> { |
2699 | if !self.options.disable_header_comment { |
2700 | let version = option_env!("CARGO_PKG_VERSION" ); |
2701 | let header = format!( |
2702 | "/* automatically generated by rust-bindgen {} */ \n\n" , |
2703 | version.unwrap_or("(unknown version)" ) |
2704 | ); |
2705 | writer.write_all(header.as_bytes())?; |
2706 | } |
2707 | |
2708 | for line in self.options.raw_lines.iter() { |
2709 | writer.write_all(line.as_bytes())?; |
2710 | writer.write_all(" \n" .as_bytes())?; |
2711 | } |
2712 | |
2713 | if !self.options.raw_lines.is_empty() { |
2714 | writer.write_all(" \n" .as_bytes())?; |
2715 | } |
2716 | |
2717 | let bindings = self.module.to_string(); |
2718 | |
2719 | match self.rustfmt_generated_string(&bindings) { |
2720 | Ok(rustfmt_bindings) => { |
2721 | writer.write_all(rustfmt_bindings.as_bytes())?; |
2722 | } |
2723 | Err(err) => { |
2724 | eprintln!( |
2725 | "Failed to run rustfmt: {} (non-fatal, continuing)" , |
2726 | err |
2727 | ); |
2728 | writer.write_all(bindings.as_bytes())?; |
2729 | } |
2730 | } |
2731 | Ok(()) |
2732 | } |
2733 | |
2734 | /// Gets the rustfmt path to rustfmt the generated bindings. |
2735 | fn rustfmt_path(&self) -> io::Result<Cow<PathBuf>> { |
2736 | debug_assert!(self.options.rustfmt_bindings); |
2737 | if let Some(ref p) = self.options.rustfmt_path { |
2738 | return Ok(Cow::Borrowed(p)); |
2739 | } |
2740 | if let Ok(rustfmt) = env::var("RUSTFMT" ) { |
2741 | return Ok(Cow::Owned(rustfmt.into())); |
2742 | } |
2743 | #[cfg (feature = "which-rustfmt" )] |
2744 | match which::which("rustfmt" ) { |
2745 | Ok(p) => Ok(Cow::Owned(p)), |
2746 | Err(e) => { |
2747 | Err(io::Error::new(io::ErrorKind::Other, format!(" {}" , e))) |
2748 | } |
2749 | } |
2750 | #[cfg (not(feature = "which-rustfmt" ))] |
2751 | // No rustfmt binary was specified, so assume that the binary is called |
2752 | // "rustfmt" and that it is in the user's PATH. |
2753 | Ok(Cow::Owned("rustfmt" .into())) |
2754 | } |
2755 | |
2756 | /// Checks if rustfmt_bindings is set and runs rustfmt on the string |
2757 | fn rustfmt_generated_string<'a>( |
2758 | &self, |
2759 | source: &'a str, |
2760 | ) -> io::Result<Cow<'a, str>> { |
2761 | let _t = time::Timer::new("rustfmt_generated_string" ) |
2762 | .with_output(self.options.time_phases); |
2763 | |
2764 | if !self.options.rustfmt_bindings { |
2765 | return Ok(Cow::Borrowed(source)); |
2766 | } |
2767 | |
2768 | let rustfmt = self.rustfmt_path()?; |
2769 | let mut cmd = Command::new(&*rustfmt); |
2770 | |
2771 | cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); |
2772 | |
2773 | if let Some(path) = self |
2774 | .options |
2775 | .rustfmt_configuration_file |
2776 | .as_ref() |
2777 | .and_then(|f| f.to_str()) |
2778 | { |
2779 | cmd.args(["--config-path" , path]); |
2780 | } |
2781 | |
2782 | let mut child = cmd.spawn()?; |
2783 | let mut child_stdin = child.stdin.take().unwrap(); |
2784 | let mut child_stdout = child.stdout.take().unwrap(); |
2785 | |
2786 | let source = source.to_owned(); |
2787 | |
2788 | // Write to stdin in a new thread, so that we can read from stdout on this |
2789 | // thread. This keeps the child from blocking on writing to its stdout which |
2790 | // might block us from writing to its stdin. |
2791 | let stdin_handle = ::std::thread::spawn(move || { |
2792 | let _ = child_stdin.write_all(source.as_bytes()); |
2793 | source |
2794 | }); |
2795 | |
2796 | let mut output = vec![]; |
2797 | io::copy(&mut child_stdout, &mut output)?; |
2798 | |
2799 | let status = child.wait()?; |
2800 | let source = stdin_handle.join().expect( |
2801 | "The thread writing to rustfmt's stdin doesn't do \ |
2802 | anything that could panic" , |
2803 | ); |
2804 | |
2805 | match String::from_utf8(output) { |
2806 | Ok(bindings) => match status.code() { |
2807 | Some(0) => Ok(Cow::Owned(bindings)), |
2808 | Some(2) => Err(io::Error::new( |
2809 | io::ErrorKind::Other, |
2810 | "Rustfmt parsing errors." .to_string(), |
2811 | )), |
2812 | Some(3) => { |
2813 | warn!("Rustfmt could not format some lines." ); |
2814 | Ok(Cow::Owned(bindings)) |
2815 | } |
2816 | _ => Err(io::Error::new( |
2817 | io::ErrorKind::Other, |
2818 | "Internal rustfmt error" .to_string(), |
2819 | )), |
2820 | }, |
2821 | _ => Ok(Cow::Owned(source)), |
2822 | } |
2823 | } |
2824 | |
2825 | /// Emit all the warning messages raised while generating the bindings in a build script. |
2826 | /// |
2827 | /// If you are using `bindgen` outside of a build script you should use [`Bindings::warnings`] |
2828 | /// and handle the messages accordingly instead. |
2829 | #[inline ] |
2830 | pub fn emit_warnings(&self) { |
2831 | for message in &self.warnings { |
2832 | println!("cargo:warning= {}" , message); |
2833 | } |
2834 | } |
2835 | |
2836 | /// Return all the warning messages raised while generating the bindings. |
2837 | #[inline ] |
2838 | pub fn warnings(&self) -> &[String] { |
2839 | &self.warnings |
2840 | } |
2841 | } |
2842 | |
2843 | impl std::fmt::Display for Bindings { |
2844 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
2845 | let mut bytes: Vec = vec![]; |
2846 | self.write(Box::new(&mut bytes) as Box<dyn Write>) |
2847 | .expect(msg:"writing to a vec cannot fail" ); |
2848 | f.write_str( |
2849 | data:std::str::from_utf8(&bytes) |
2850 | .expect(msg:"we should only write bindings that are valid utf-8" ), |
2851 | ) |
2852 | } |
2853 | } |
2854 | |
2855 | /// Determines whether the given cursor is in any of the files matched by the |
2856 | /// options. |
2857 | fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool { |
2858 | ctx.options().builtins || !cursor.is_builtin() |
2859 | } |
2860 | |
2861 | /// Parse one `Item` from the Clang cursor. |
2862 | fn parse_one( |
2863 | ctx: &mut BindgenContext, |
2864 | cursor: clang::Cursor, |
2865 | parent: Option<ItemId>, |
2866 | ) -> clang_sys::CXChildVisitResult { |
2867 | if !filter_builtins(ctx, &cursor) { |
2868 | return CXChildVisit_Continue; |
2869 | } |
2870 | |
2871 | use clang_sys::CXChildVisit_Continue; |
2872 | match Item::parse(cursor, parent_id:parent, ctx) { |
2873 | Ok(..) => {} |
2874 | Err(ParseError::Continue) => {} |
2875 | Err(ParseError::Recurse) => { |
2876 | cursor.visit(|child: Cursor| parse_one(ctx, cursor:child, parent)); |
2877 | } |
2878 | } |
2879 | CXChildVisit_Continue |
2880 | } |
2881 | |
2882 | /// Parse the Clang AST into our `Item` internal representation. |
2883 | fn parse(context: &mut BindgenContext) -> Result<(), BindgenError> { |
2884 | use clang_sys::*; |
2885 | |
2886 | let mut error = None; |
2887 | for d in context.translation_unit().diags().iter() { |
2888 | let msg = d.format(); |
2889 | let is_err = d.severity() >= CXDiagnostic_Error; |
2890 | if is_err { |
2891 | let error = error.get_or_insert_with(String::new); |
2892 | error.push_str(&msg); |
2893 | error.push(' \n' ); |
2894 | } else { |
2895 | eprintln!("clang diag: {}" , msg); |
2896 | } |
2897 | } |
2898 | |
2899 | if let Some(message) = error { |
2900 | return Err(BindgenError::ClangDiagnostic(message)); |
2901 | } |
2902 | |
2903 | let cursor = context.translation_unit().cursor(); |
2904 | |
2905 | if context.options().emit_ast { |
2906 | fn dump_if_not_builtin(cur: &clang::Cursor) -> CXChildVisitResult { |
2907 | if !cur.is_builtin() { |
2908 | clang::ast_dump(cur, 0) |
2909 | } else { |
2910 | CXChildVisit_Continue |
2911 | } |
2912 | } |
2913 | cursor.visit(|cur| dump_if_not_builtin(&cur)); |
2914 | } |
2915 | |
2916 | let root = context.root_module(); |
2917 | context.with_module(root, |context| { |
2918 | cursor.visit(|cursor| parse_one(context, cursor, None)) |
2919 | }); |
2920 | |
2921 | assert!( |
2922 | context.current_module() == context.root_module(), |
2923 | "How did this happen?" |
2924 | ); |
2925 | Ok(()) |
2926 | } |
2927 | |
2928 | /// Extracted Clang version data |
2929 | #[derive (Debug)] |
2930 | pub struct ClangVersion { |
2931 | /// Major and minor semver, if parsing was successful |
2932 | pub parsed: Option<(u32, u32)>, |
2933 | /// full version string |
2934 | pub full: String, |
2935 | } |
2936 | |
2937 | /// Get the major and the minor semver numbers of Clang's version |
2938 | pub fn clang_version() -> ClangVersion { |
2939 | ensure_libclang_is_loaded(); |
2940 | |
2941 | //Debian clang version 11.0.1-2 |
2942 | let raw_v: String = clang::extract_clang_version(); |
2943 | let split_v: Option<Vec<&str>> = raw_v |
2944 | .split_whitespace() |
2945 | .find(|t| t.chars().next().map_or(false, |v| v.is_ascii_digit())) |
2946 | .map(|v| v.split('.' ).collect()); |
2947 | if let Some(v) = split_v { |
2948 | if v.len() >= 2 { |
2949 | let maybe_major = v[0].parse::<u32>(); |
2950 | let maybe_minor = v[1].parse::<u32>(); |
2951 | if let (Ok(major), Ok(minor)) = (maybe_major, maybe_minor) { |
2952 | return ClangVersion { |
2953 | parsed: Some((major, minor)), |
2954 | full: raw_v.clone(), |
2955 | }; |
2956 | } |
2957 | } |
2958 | }; |
2959 | ClangVersion { |
2960 | parsed: None, |
2961 | full: raw_v.clone(), |
2962 | } |
2963 | } |
2964 | |
2965 | /// Looks for the env var `var_${TARGET}`, and falls back to just `var` when it is not found. |
2966 | fn get_target_dependent_env_var(var: &str) -> Option<String> { |
2967 | if let Ok(target: String) = env::var(key:"TARGET" ) { |
2968 | if let Ok(v: String) = env::var(key:format!(" {}_ {}" , var, target)) { |
2969 | return Some(v); |
2970 | } |
2971 | if let Ok(v: String) = env::var(key:format!(" {}_ {}" , var, target.replace('-' , "_" ))) |
2972 | { |
2973 | return Some(v); |
2974 | } |
2975 | } |
2976 | env::var(key:var).ok() |
2977 | } |
2978 | |
2979 | /// A ParseCallbacks implementation that will act on file includes by echoing a rerun-if-changed |
2980 | /// line |
2981 | /// |
2982 | /// When running inside a `build.rs` script, this can be used to make cargo invalidate the |
2983 | /// generated bindings whenever any of the files included from the header change: |
2984 | /// ``` |
2985 | /// use bindgen::builder; |
2986 | /// let bindings = builder() |
2987 | /// .header("path/to/input/header" ) |
2988 | /// .parse_callbacks(Box::new(bindgen::CargoCallbacks)) |
2989 | /// .generate(); |
2990 | /// ``` |
2991 | #[derive (Debug)] |
2992 | pub struct CargoCallbacks; |
2993 | |
2994 | impl callbacks::ParseCallbacks for CargoCallbacks { |
2995 | fn include_file(&self, filename: &str) { |
2996 | println!("cargo:rerun-if-changed= {}" , filename); |
2997 | } |
2998 | } |
2999 | |
3000 | /// Test command_line_flag function. |
3001 | #[test ] |
3002 | fn commandline_flag_unit_test_function() { |
3003 | //Test 1 |
3004 | let bindings = crate::builder(); |
3005 | let command_line_flags = bindings.command_line_flags(); |
3006 | |
3007 | let test_cases = vec![ |
3008 | "--rust-target" , |
3009 | "--no-derive-default" , |
3010 | "--generate" , |
3011 | "functions,types,vars,methods,constructors,destructors" , |
3012 | ] |
3013 | .iter() |
3014 | .map(|&x| x.into()) |
3015 | .collect::<Vec<String>>(); |
3016 | |
3017 | assert!(test_cases.iter().all(|x| command_line_flags.contains(x))); |
3018 | |
3019 | //Test 2 |
3020 | let bindings = crate::builder() |
3021 | .header("input_header" ) |
3022 | .allowlist_type("Distinct_Type" ) |
3023 | .allowlist_function("safe_function" ); |
3024 | |
3025 | let command_line_flags = bindings.command_line_flags(); |
3026 | let test_cases = vec![ |
3027 | "--rust-target" , |
3028 | "input_header" , |
3029 | "--no-derive-default" , |
3030 | "--generate" , |
3031 | "functions,types,vars,methods,constructors,destructors" , |
3032 | "--allowlist-type" , |
3033 | "Distinct_Type" , |
3034 | "--allowlist-function" , |
3035 | "safe_function" , |
3036 | ] |
3037 | .iter() |
3038 | .map(|&x| x.into()) |
3039 | .collect::<Vec<String>>(); |
3040 | println!(" {:?}" , command_line_flags); |
3041 | |
3042 | assert!(test_cases.iter().all(|x| command_line_flags.contains(x))); |
3043 | } |
3044 | |
3045 | #[test ] |
3046 | fn test_rust_to_clang_target() { |
3047 | assert_eq!(rust_to_clang_target("aarch64-apple-ios" ), "arm64-apple-ios" ); |
3048 | } |
3049 | |
3050 | #[test ] |
3051 | fn test_rust_to_clang_target_riscv() { |
3052 | assert_eq!( |
3053 | rust_to_clang_target("riscv64gc-unknown-linux-gnu" ), |
3054 | "riscv64-unknown-linux-gnu" |
3055 | ) |
3056 | } |
3057 | |
3058 | #[test ] |
3059 | fn test_rust_to_clang_target_espidf() { |
3060 | assert_eq!( |
3061 | rust_to_clang_target("riscv32imc-esp-espidf" ), |
3062 | "riscv32-esp-elf" |
3063 | ); |
3064 | assert_eq!( |
3065 | rust_to_clang_target("xtensa-esp32-espidf" ), |
3066 | "xtensa-esp32-elf" |
3067 | ); |
3068 | } |
3069 | |