1use bindgen::callbacks::TypeKind;
2use bindgen::{
3    builder, AliasVariation, Builder, CodegenConfig, EnumVariation,
4    MacroTypeVariation, NonCopyUnionStyle, RegexSet, RustTarget,
5    DEFAULT_ANON_FIELDS_PREFIX, RUST_TARGET_STRINGS,
6};
7use clap::Parser;
8use std::fs::File;
9use std::io::{self, Error, ErrorKind};
10use std::path::PathBuf;
11
12fn rust_target_help() -> String {
13    format!(
14        "Version of the Rust compiler to target. Valid options are: {:?}. Defaults to {:?}.",
15        RUST_TARGET_STRINGS,
16        String::from(RustTarget::default())
17    )
18}
19
20fn parse_codegen_config(what_to_generate: &str) -> io::Result<CodegenConfig> {
21    let mut config = CodegenConfig::empty();
22    for what in what_to_generate.split(',') {
23        match what {
24            "functions" => config.insert(CodegenConfig::FUNCTIONS),
25            "types" => config.insert(CodegenConfig::TYPES),
26            "vars" => config.insert(CodegenConfig::VARS),
27            "methods" => config.insert(CodegenConfig::METHODS),
28            "constructors" => config.insert(CodegenConfig::CONSTRUCTORS),
29            "destructors" => config.insert(CodegenConfig::DESTRUCTORS),
30            otherwise => {
31                return Err(Error::new(
32                    ErrorKind::Other,
33                    format!("Unknown generate item: {}", otherwise),
34                ));
35            }
36        }
37    }
38
39    Ok(config)
40}
41
42#[derive(Parser, Debug)]
43#[clap(
44    about = "Generates Rust bindings from C/C++ headers.",
45    override_usage = "bindgen [FLAGS] [OPTIONS] [HEADER] -- [CLANG_ARGS]...",
46    trailing_var_arg = true
47)]
48struct BindgenCommand {
49    /// C or C++ header file.
50    header: Option<String>,
51    /// Path to write depfile to.
52    #[arg(long)]
53    depfile: Option<String>,
54    /// The default style of code used to generate enums.
55    #[arg(long, value_name = "VARIANT")]
56    default_enum_style: Option<EnumVariation>,
57    /// Mark any enum whose name matches <REGEX> as a set of bitfield flags.
58    #[arg(long, value_name = "REGEX")]
59    bitfield_enum: Vec<String>,
60    /// Mark any enum whose name matches <REGEX> as a newtype.
61    #[arg(long, value_name = "REGEX")]
62    newtype_enum: Vec<String>,
63    /// Mark any enum whose name matches <REGEX> as a global newtype.
64    #[arg(long, value_name = "REGEX")]
65    newtype_global_enum: Vec<String>,
66    /// Mark any enum whose name matches <REGEX> as a Rust enum.
67    #[arg(long, value_name = "REGEX")]
68    rustified_enum: Vec<String>,
69    /// Mark any enum whose name matches <REGEX> as a series of constants.
70    #[arg(long, value_name = "REGEX")]
71    constified_enum: Vec<String>,
72    /// Mark any enum whose name matches <regex> as a module of constants.
73    #[arg(long, value_name = "REGEX")]
74    constified_enum_module: Vec<String>,
75    /// The default signed/unsigned type for C macro constants.
76    #[arg(long, value_name = "VARIANT")]
77    default_macro_constant_type: Option<MacroTypeVariation>,
78    /// The default style of code used to generate typedefs.
79    #[arg(long, value_name = "VARIANT")]
80    default_alias_style: Option<AliasVariation>,
81    /// Mark any typedef alias whose name matches <REGEX> to use normal type aliasing.
82    #[arg(long, value_name = "REGEX")]
83    normal_alias: Vec<String>,
84    /// Mark any typedef alias whose name matches <REGEX> to have a new type generated for it.
85    #[arg(long, value_name = "REGEX")]
86    new_type_alias: Vec<String>,
87    /// Mark any typedef alias whose name matches <REGEX> to have a new type with Deref and DerefMut to the inner type.
88    #[arg(long, value_name = "REGEX")]
89    new_type_alias_deref: Vec<String>,
90    /// The default style of code used to generate unions with non-Copy members. Note that ManuallyDrop was first stabilized in Rust 1.20.0.
91    #[arg(long, value_name = "STYLE")]
92    default_non_copy_union_style: Option<NonCopyUnionStyle>,
93    /// Mark any union whose name matches <REGEX> and who has a non-Copy member to use a bindgen-generated wrapper for fields.
94    #[arg(long, value_name = "REGEX")]
95    bindgen_wrapper_union: Vec<String>,
96    /// Mark any union whose name matches <REGEX> and who has a non-Copy member to use ManuallyDrop (stabilized in Rust 1.20.0) for fields.
97    #[arg(long, value_name = "REGEX")]
98    manually_drop_union: Vec<String>,
99    /// Mark <TYPE> as hidden.
100    #[arg(long, value_name = "TYPE")]
101    blocklist_type: Vec<String>,
102    /// Mark <FUNCTION> as hidden.
103    #[arg(long, value_name = "FUNCTION")]
104    blocklist_function: Vec<String>,
105    /// Mark <ITEM> as hidden.
106    #[arg(long, value_name = "ITEM")]
107    blocklist_item: Vec<String>,
108    /// Mark <FILE> as hidden.
109    #[arg(long, value_name = "FILE")]
110    blocklist_file: Vec<String>,
111    /// Avoid generating layout tests for any type.
112    #[arg(long)]
113    no_layout_tests: bool,
114    /// Avoid deriving Copy on any type.
115    #[arg(long)]
116    no_derive_copy: bool,
117    /// Avoid deriving Debug on any type.
118    #[arg(long)]
119    no_derive_debug: bool,
120    /// Avoid deriving Default on any type.
121    #[arg(long, hide = true)]
122    no_derive_default: bool,
123    /// Create a Debug implementation if it cannot be derived automatically.
124    #[arg(long)]
125    impl_debug: bool,
126    /// Create a PartialEq implementation if it cannot be derived automatically.
127    #[arg(long)]
128    impl_partialeq: bool,
129    /// Derive Default on any type.
130    #[arg(long)]
131    with_derive_default: bool,
132    /// Derive Hash on any type.docstring
133    #[arg(long)]
134    with_derive_hash: bool,
135    /// Derive PartialEq on any type.
136    #[arg(long)]
137    with_derive_partialeq: bool,
138    /// Derive PartialOrd on any type.
139    #[arg(long)]
140    with_derive_partialord: bool,
141    /// Derive Eq on any type.
142    #[arg(long)]
143    with_derive_eq: bool,
144    /// Derive Ord on any type.
145    #[arg(long)]
146    with_derive_ord: bool,
147    /// Avoid including doc comments in the output, see: https://github.com/rust-lang/rust-bindgen/issues/426
148    #[arg(long)]
149    no_doc_comments: bool,
150    /// Disable allowlisting types recursively. This will cause bindgen to emit Rust code that won't compile! See the `bindgen::Builder::allowlist_recursively` method's documentation for details.
151    #[arg(long)]
152    no_recursive_allowlist: bool,
153    /// Use extern crate instead of use for objc.
154    #[arg(long)]
155    objc_extern_crate: bool,
156    /// Generate block signatures instead of void pointers.
157    #[arg(long)]
158    generate_block: bool,
159    /// Use extern crate instead of use for block.
160    #[arg(long)]
161    block_extern_crate: bool,
162    /// Do not trust the libclang-provided mangling
163    #[arg(long)]
164    distrust_clang_mangling: bool,
165    /// Output bindings for builtin definitions, e.g. __builtin_va_list.
166    #[arg(long)]
167    builtins: bool,
168    /// Use the given prefix before raw types instead of ::std::os::raw.
169    #[arg(long, value_name = "PREFIX")]
170    ctypes_prefix: Option<String>,
171    /// Use the given prefix for anonymous fields.
172    #[arg(long, default_value = DEFAULT_ANON_FIELDS_PREFIX, value_name = "PREFIX")]
173    anon_fields_prefix: String,
174    /// Time the different bindgen phases and print to stderr
175    #[arg(long)]
176    time_phases: bool,
177    /// Output the Clang AST for debugging purposes.
178    #[arg(long)]
179    emit_clang_ast: bool,
180    /// Output our internal IR for debugging purposes.
181    #[arg(long)]
182    emit_ir: bool,
183    /// Dump graphviz dot file.
184    #[arg(long, value_name = "PATH")]
185    emit_ir_graphviz: Option<String>,
186    /// Enable support for C++ namespaces.
187    #[arg(long)]
188    enable_cxx_namespaces: bool,
189    /// Disable namespacing via mangling, causing bindgen to generate names like `Baz` instead of `foo_bar_Baz` for an input name `foo::bar::Baz`.
190    #[arg(long)]
191    disable_name_namespacing: bool,
192    /// Disable nested struct naming, causing bindgen to generate names like `bar` instead of `foo_bar` for a nested definition `struct foo { struct bar { } b; };`.
193    #[arg(long)]
194    disable_nested_struct_naming: bool,
195    /// Disable support for native Rust unions.
196    #[arg(long)]
197    disable_untagged_union: bool,
198    /// Suppress insertion of bindgen's version identifier into generated bindings.
199    #[arg(long)]
200    disable_header_comment: bool,
201    /// Do not generate bindings for functions or methods. This is useful when you only care about struct layouts.docstring
202    #[arg(long)]
203    ignore_functions: bool,
204    /// Generate only given items, split by commas. Valid values are `functions`,`types`, `vars`, `methods`, `constructors` and `destructors`.
205    #[arg(long, value_parser = parse_codegen_config)]
206    generate: Option<CodegenConfig>,
207    /// Do not generate bindings for methods.
208    #[arg(long)]
209    ignore_methods: bool,
210    /// Do not automatically convert floats to f32/f64.
211    #[arg(long)]
212    no_convert_floats: bool,
213    /// Do not prepend the enum name to constant or newtype variants.
214    #[arg(long)]
215    no_prepend_enum_name: bool,
216    /// Do not try to detect default include paths
217    #[arg(long)]
218    no_include_path_detection: bool,
219    /// Try to fit macro constants into types smaller than u32/i32
220    #[arg(long)]
221    fit_macro_constant_types: bool,
222    /// Mark <TYPE> as opaque.
223    #[arg(long, value_name = "TYPE")]
224    opaque_type: Vec<String>,
225    ///  Write Rust bindings to <OUTPUT>.
226    #[arg(long, short, value_name = "OUTPUT")]
227    output: Option<String>,
228    /// Add a raw line of Rust code at the beginning of output.
229    #[arg(long)]
230    raw_line: Vec<String>,
231    /// Add a raw line of Rust code to a given module.
232    #[arg(long, number_of_values = 2, value_names = ["MODULE-NAME", "RAW-LINE"])]
233    module_raw_line: Vec<String>,
234    #[arg(long, help = rust_target_help())]
235    rust_target: Option<RustTarget>,
236    /// Use types from Rust core instead of std.
237    #[arg(long)]
238    use_core: bool,
239    /// Conservatively generate inline namespaces to avoid name conflicts.
240    #[arg(long)]
241    conservative_inline_namespaces: bool,
242    /// MSVC C++ ABI mangling. DEPRECATED: Has no effect.
243    #[arg(long)]
244    use_msvc_mangling: bool,
245    /// Allowlist all the free-standing functions matching <REGEX>. Other non-allowlisted functions will not be generated.
246    #[arg(long, value_name = "REGEX")]
247    allowlist_function: Vec<String>,
248    /// Generate inline functions.
249    #[arg(long)]
250    generate_inline_functions: bool,
251    /// Only generate types matching <REGEX>. Other non-allowlisted types will not be generated.
252    #[arg(long, value_name = "REGEX")]
253    allowlist_type: Vec<String>,
254    /// Allowlist all the free-standing variables matching <REGEX>. Other non-allowlisted variables will not be generated.
255    #[arg(long, value_name = "REGEX")]
256    allowlist_var: Vec<String>,
257    /// Allowlist all contents of <PATH>.
258    #[arg(long, value_name = "PATH")]
259    allowlist_file: Vec<String>,
260    /// Print verbose error messages.
261    #[arg(long)]
262    verbose: bool,
263    /// Preprocess and dump the input header files to disk. Useful when debugging bindgen, using C-Reduce, or when filing issues. The resulting file will be named something like `__bindgen.i` or `__bindgen.ii`.
264    #[arg(long)]
265    dump_preprocessed_input: bool,
266    /// Do not record matching items in the regex sets. This disables reporting of unused items.
267    #[arg(long)]
268    no_record_matches: bool,
269    /// Ignored - this is enabled by default.
270    #[arg(long = "size_t-is-usize")]
271    size_t_is_usize: bool,
272    /// Do not bind size_t as usize (useful on platforms where those types are incompatible).
273    #[arg(long = "no-size_t-is-usize")]
274    no_size_t_is_usize: bool,
275    /// Do not format the generated bindings with rustfmt.
276    #[arg(long)]
277    no_rustfmt_bindings: bool,
278    /// Format the generated bindings with rustfmt. DEPRECATED: --rustfmt-bindings is now enabled by default. Disable with --no-rustfmt-bindings.
279    #[arg(long)]
280    rustfmt_bindings: bool,
281    /// The absolute path to the rustfmt configuration file. The configuration file will be used for formatting the bindings. This parameter is incompatible with --no-rustfmt-bindings.
282    #[arg(long, value_name = "PATH")]
283    rustfmt_configuration_file: Option<String>,
284    /// Avoid deriving PartialEq for types matching <REGEX>.
285    #[arg(long, value_name = "REGEX")]
286    no_partialeq: Vec<String>,
287    /// Avoid deriving Copy for types matching <REGEX>.
288    #[arg(long, value_name = "REGEX")]
289    no_copy: Vec<String>,
290    /// Avoid deriving Debug for types matching <REGEX>.
291    #[arg(long, value_name = "REGEX")]
292    no_debug: Vec<String>,
293    /// Avoid deriving/implementing Default for types matching <REGEX>.
294    #[arg(long, value_name = "REGEX")]
295    no_default: Vec<String>,
296    /// Avoid deriving Hash for types matching <REGEX>.
297    #[arg(long, value_name = "REGEX")]
298    no_hash: Vec<String>,
299    /// Add #[must_use] annotation to types matching <REGEX>.
300    #[arg(long, value_name = "REGEX")]
301    must_use_type: Vec<String>,
302    /// Enables detecting unexposed attributes in functions (slow). Used to generate #[must_use] annotations.
303    #[arg(long)]
304    enable_function_attribute_detection: bool,
305    /// Use `*const [T; size]` instead of `*const T` for C arrays
306    #[arg(long)]
307    use_array_pointers_in_arguments: bool,
308    /// The name to be used in a #[link(wasm_import_module = ...)] statement
309    #[arg(long, value_name = "NAME")]
310    wasm_import_module_name: Option<String>,
311    /// Use dynamic loading mode with the given library name.
312    #[arg(long, value_name = "NAME")]
313    dynamic_loading: Option<String>,
314    /// Require successful linkage to all functions in the library.
315    #[arg(long)]
316    dynamic_link_require_all: bool,
317    /// Makes generated bindings `pub` only for items if the items are publically accessible in C++.
318    #[arg(long)]
319    respect_cxx_access_specs: bool,
320    /// Always translate enum integer types to native Rust integer types.
321    #[arg(long)]
322    translate_enum_integer_types: bool,
323    /// Generate types with C style naming.
324    #[arg(long)]
325    c_naming: bool,
326    /// Always output explicit padding fields.
327    #[arg(long)]
328    explicit_padding: bool,
329    /// Enables generation of vtable functions.
330    #[arg(long)]
331    vtable_generation: bool,
332    /// Enables sorting of code generation in a predefined manner.
333    #[arg(long)]
334    sort_semantically: bool,
335    /// Deduplicates extern blocks.
336    #[arg(long)]
337    merge_extern_blocks: bool,
338    /// Overrides the ABI of functions matching <regex>. The <OVERRIDE> value must be of the shape <REGEX>=<ABI> where <ABI> can be one of C, stdcall, fastcall, thiscall, aapcs, win64 or C-unwind.
339    #[arg(long, value_name = "OVERRIDE")]
340    override_abi: Vec<String>,
341    /// Wrap unsafe operations in unsafe blocks.
342    #[arg(long)]
343    wrap_unsafe_ops: bool,
344    /// Derive custom traits on any kind of type. The <CUSTOM> value must be of the shape <REGEX>=<DERIVE> where <DERIVE> is a coma-separated list of derive macros.
345    #[arg(long, value_name = "CUSTOM")]
346    with_derive_custom: Vec<String>,
347    /// Derive custom traits on a `struct`. The <CUSTOM> value must be of the shape <REGEX>=<DERIVE> where <DERIVE> is a coma-separated list of derive macros.
348    #[arg(long, value_name = "CUSTOM")]
349    with_derive_custom_struct: Vec<String>,
350    /// Derive custom traits on an `enum. The <CUSTOM> value must be of the shape <REGEX>=<DERIVE> where <DERIVE> is a coma-separated list of derive macros.
351    #[arg(long, value_name = "CUSTOM")]
352    with_derive_custom_enum: Vec<String>,
353    /// Derive custom traits on a `union`. The <CUSTOM> value must be of the shape <REGEX>=<DERIVE> where <DERIVE> is a coma-separated list of derive macros.
354    #[arg(long, value_name = "CUSTOM")]
355    with_derive_custom_union: Vec<String>,
356    /// Generate wrappers for `static` and `static inline` functions.
357    #[arg(long, requires = "experimental")]
358    wrap_static_fns: bool,
359    /// Sets the path for the source file that must be created due to the presence of `static` and
360    /// `static inline` functions.
361    #[arg(long, requires = "experimental", value_name = "PATH")]
362    wrap_static_fns_path: Option<PathBuf>,
363    /// Sets the suffix added to the extern wrapper functions generated for `static` and `static
364    /// inline` functions.
365    #[arg(long, requires = "experimental", value_name = "SUFFIX")]
366    wrap_static_fns_suffix: Option<String>,
367    /// Enables experimental features.
368    #[arg(long)]
369    experimental: bool,
370    /// Prints the version, and exits
371    #[arg(short = 'V', long)]
372    version: bool,
373    /// Arguments to be passed straight through to clang.
374    clang_args: Vec<String>,
375}
376
377/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
378pub fn builder_from_flags<I>(
379    args: I,
380) -> Result<(Builder, Box<dyn io::Write>, bool), io::Error>
381where
382    I: Iterator<Item = String>,
383{
384    let command = BindgenCommand::parse_from(args);
385
386    let BindgenCommand {
387        header,
388        depfile,
389        default_enum_style,
390        bitfield_enum,
391        newtype_enum,
392        newtype_global_enum,
393        rustified_enum,
394        constified_enum,
395        constified_enum_module,
396        default_macro_constant_type,
397        default_alias_style,
398        normal_alias,
399        new_type_alias,
400        new_type_alias_deref,
401        default_non_copy_union_style,
402        bindgen_wrapper_union,
403        manually_drop_union,
404        blocklist_type,
405        blocklist_function,
406        blocklist_item,
407        blocklist_file,
408        no_layout_tests,
409        no_derive_copy,
410        no_derive_debug,
411        no_derive_default,
412        impl_debug,
413        impl_partialeq,
414        with_derive_default,
415        with_derive_hash,
416        with_derive_partialeq,
417        with_derive_partialord,
418        with_derive_eq,
419        with_derive_ord,
420        no_doc_comments,
421        no_recursive_allowlist,
422        objc_extern_crate,
423        generate_block,
424        block_extern_crate,
425        distrust_clang_mangling,
426        builtins,
427        ctypes_prefix,
428        anon_fields_prefix,
429        time_phases,
430        emit_clang_ast,
431        emit_ir,
432        emit_ir_graphviz,
433        enable_cxx_namespaces,
434        disable_name_namespacing,
435        disable_nested_struct_naming,
436        disable_untagged_union,
437        disable_header_comment,
438        ignore_functions,
439        generate,
440        ignore_methods,
441        no_convert_floats,
442        no_prepend_enum_name,
443        no_include_path_detection,
444        fit_macro_constant_types,
445        opaque_type,
446        output,
447        raw_line,
448        module_raw_line,
449        rust_target,
450        use_core,
451        conservative_inline_namespaces,
452        use_msvc_mangling: _,
453        allowlist_function,
454        generate_inline_functions,
455        allowlist_type,
456        allowlist_var,
457        allowlist_file,
458        verbose,
459        dump_preprocessed_input,
460        no_record_matches,
461        size_t_is_usize: _,
462        no_size_t_is_usize,
463        no_rustfmt_bindings,
464        rustfmt_bindings: _,
465        rustfmt_configuration_file,
466        no_partialeq,
467        no_copy,
468        no_debug,
469        no_default,
470        no_hash,
471        must_use_type,
472        enable_function_attribute_detection,
473        use_array_pointers_in_arguments,
474        wasm_import_module_name,
475        dynamic_loading,
476        dynamic_link_require_all,
477        respect_cxx_access_specs,
478        translate_enum_integer_types,
479        c_naming,
480        explicit_padding,
481        vtable_generation,
482        sort_semantically,
483        merge_extern_blocks,
484        override_abi,
485        wrap_unsafe_ops,
486        with_derive_custom,
487        with_derive_custom_struct,
488        with_derive_custom_enum,
489        with_derive_custom_union,
490        wrap_static_fns,
491        wrap_static_fns_path,
492        wrap_static_fns_suffix,
493        experimental: _,
494        version,
495        clang_args,
496    } = command;
497
498    if version {
499        println!(
500            "bindgen {}",
501            option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
502        );
503        if verbose {
504            println!("Clang: {}", bindgen::clang_version().full);
505        }
506        std::process::exit(0);
507    }
508
509    let mut builder = builder();
510
511    if let Some(header) = header {
512        builder = builder.header(header);
513    } else {
514        return Err(Error::new(ErrorKind::Other, "Header not found"));
515    }
516
517    if let Some(rust_target) = rust_target {
518        builder = builder.rust_target(rust_target);
519    }
520
521    if let Some(variant) = default_enum_style {
522        builder = builder.default_enum_style(variant);
523    }
524
525    for regex in bitfield_enum {
526        builder = builder.bitfield_enum(regex);
527    }
528
529    for regex in newtype_enum {
530        builder = builder.newtype_enum(regex);
531    }
532
533    for regex in newtype_global_enum {
534        builder = builder.newtype_global_enum(regex);
535    }
536
537    for regex in rustified_enum {
538        builder = builder.rustified_enum(regex);
539    }
540
541    for regex in constified_enum {
542        builder = builder.constified_enum(regex);
543    }
544
545    for regex in constified_enum_module {
546        builder = builder.constified_enum_module(regex);
547    }
548
549    if let Some(default_macro_constant_type) = default_macro_constant_type {
550        builder =
551            builder.default_macro_constant_type(default_macro_constant_type)
552    }
553
554    if let Some(variant) = default_alias_style {
555        builder = builder.default_alias_style(variant);
556    }
557
558    for regex in normal_alias {
559        builder = builder.type_alias(regex);
560    }
561
562    for regex in new_type_alias {
563        builder = builder.new_type_alias(regex);
564    }
565
566    for regex in new_type_alias_deref {
567        builder = builder.new_type_alias_deref(regex);
568    }
569
570    if let Some(variant) = default_non_copy_union_style {
571        builder = builder.default_non_copy_union_style(variant);
572    }
573
574    for regex in bindgen_wrapper_union {
575        builder = builder.bindgen_wrapper_union(regex);
576    }
577
578    for regex in manually_drop_union {
579        builder = builder.manually_drop_union(regex);
580    }
581
582    for ty in blocklist_type {
583        builder = builder.blocklist_type(ty);
584    }
585
586    for fun in blocklist_function {
587        builder = builder.blocklist_function(fun);
588    }
589
590    for id in blocklist_item {
591        builder = builder.blocklist_item(id);
592    }
593
594    for file in blocklist_file {
595        builder = builder.blocklist_file(file);
596    }
597
598    if builtins {
599        builder = builder.emit_builtins();
600    }
601
602    if no_layout_tests {
603        builder = builder.layout_tests(false);
604    }
605
606    if no_derive_copy {
607        builder = builder.derive_copy(false);
608    }
609
610    if no_derive_debug {
611        builder = builder.derive_debug(false);
612    }
613
614    if impl_debug {
615        builder = builder.impl_debug(true);
616    }
617
618    if impl_partialeq {
619        builder = builder.impl_partialeq(true);
620    }
621
622    if with_derive_default {
623        builder = builder.derive_default(true);
624    }
625
626    if with_derive_hash {
627        builder = builder.derive_hash(true);
628    }
629
630    if with_derive_partialeq {
631        builder = builder.derive_partialeq(true);
632    }
633
634    if with_derive_partialord {
635        builder = builder.derive_partialord(true);
636    }
637
638    if with_derive_eq {
639        builder = builder.derive_eq(true);
640    }
641
642    if with_derive_ord {
643        builder = builder.derive_ord(true);
644    }
645
646    if no_derive_default {
647        builder = builder.derive_default(false);
648    }
649
650    if no_prepend_enum_name {
651        builder = builder.prepend_enum_name(false);
652    }
653
654    if no_include_path_detection {
655        builder = builder.detect_include_paths(false);
656    }
657
658    if fit_macro_constant_types {
659        builder = builder.fit_macro_constants(true);
660    }
661
662    if time_phases {
663        builder = builder.time_phases(true);
664    }
665
666    if use_array_pointers_in_arguments {
667        builder = builder.array_pointers_in_arguments(true);
668    }
669
670    if let Some(wasm_import_name) = wasm_import_module_name {
671        builder = builder.wasm_import_module_name(wasm_import_name);
672    }
673
674    if let Some(prefix) = ctypes_prefix {
675        builder = builder.ctypes_prefix(prefix);
676    }
677
678    builder = builder.anon_fields_prefix(anon_fields_prefix);
679
680    if let Some(config) = generate {
681        builder = builder.with_codegen_config(config);
682    }
683
684    if emit_clang_ast {
685        builder = builder.emit_clang_ast();
686    }
687
688    if emit_ir {
689        builder = builder.emit_ir();
690    }
691
692    if let Some(path) = emit_ir_graphviz {
693        builder = builder.emit_ir_graphviz(path);
694    }
695
696    if enable_cxx_namespaces {
697        builder = builder.enable_cxx_namespaces();
698    }
699
700    if enable_function_attribute_detection {
701        builder = builder.enable_function_attribute_detection();
702    }
703
704    if disable_name_namespacing {
705        builder = builder.disable_name_namespacing();
706    }
707
708    if disable_nested_struct_naming {
709        builder = builder.disable_nested_struct_naming();
710    }
711
712    if disable_untagged_union {
713        builder = builder.disable_untagged_union();
714    }
715
716    if disable_header_comment {
717        builder = builder.disable_header_comment();
718    }
719
720    if ignore_functions {
721        builder = builder.ignore_functions();
722    }
723
724    if ignore_methods {
725        builder = builder.ignore_methods();
726    }
727
728    if no_convert_floats {
729        builder = builder.no_convert_floats();
730    }
731
732    if no_doc_comments {
733        builder = builder.generate_comments(false);
734    }
735
736    if no_recursive_allowlist {
737        builder = builder.allowlist_recursively(false);
738    }
739
740    if objc_extern_crate {
741        builder = builder.objc_extern_crate(true);
742    }
743
744    if generate_block {
745        builder = builder.generate_block(true);
746    }
747
748    if block_extern_crate {
749        builder = builder.block_extern_crate(true);
750    }
751
752    for ty in opaque_type {
753        builder = builder.opaque_type(ty);
754    }
755
756    for line in raw_line {
757        builder = builder.raw_line(line);
758    }
759
760    let mut values = module_raw_line.into_iter();
761    while let Some(module) = values.next() {
762        let line = values.next().unwrap();
763        builder = builder.module_raw_line(module, line);
764    }
765
766    if use_core {
767        builder = builder.use_core();
768    }
769
770    if distrust_clang_mangling {
771        builder = builder.trust_clang_mangling(false);
772    }
773
774    if conservative_inline_namespaces {
775        builder = builder.conservative_inline_namespaces();
776    }
777
778    if generate_inline_functions {
779        builder = builder.generate_inline_functions(true);
780    }
781
782    for regex in allowlist_function {
783        builder = builder.allowlist_function(regex);
784    }
785
786    for regex in allowlist_type {
787        builder = builder.allowlist_type(regex);
788    }
789
790    for regex in allowlist_var {
791        builder = builder.allowlist_var(regex);
792    }
793
794    for file in allowlist_file {
795        builder = builder.allowlist_file(file);
796    }
797
798    for arg in clang_args {
799        builder = builder.clang_arg(arg);
800    }
801
802    let output = if let Some(path) = &output {
803        let file = File::create(path)?;
804        if let Some(depfile) = depfile {
805            builder = builder.depfile(path, depfile);
806        }
807        Box::new(io::BufWriter::new(file)) as Box<dyn io::Write>
808    } else {
809        if let Some(depfile) = depfile {
810            builder = builder.depfile("-", depfile);
811        }
812        Box::new(io::BufWriter::new(io::stdout())) as Box<dyn io::Write>
813    };
814
815    if dump_preprocessed_input {
816        builder.dump_preprocessed_input()?;
817    }
818
819    if no_record_matches {
820        builder = builder.record_matches(false);
821    }
822
823    if no_size_t_is_usize {
824        builder = builder.size_t_is_usize(false);
825    }
826
827    if no_rustfmt_bindings {
828        builder = builder.rustfmt_bindings(false);
829    }
830
831    if let Some(path_str) = rustfmt_configuration_file {
832        let path = PathBuf::from(path_str);
833
834        if no_rustfmt_bindings {
835            return Err(Error::new(
836                ErrorKind::Other,
837                "Cannot supply both --rustfmt-configuration-file and --no-rustfmt-bindings",
838            ));
839        }
840
841        if !path.is_absolute() {
842            return Err(Error::new(
843                ErrorKind::Other,
844                "--rustfmt-configuration--file needs to be an absolute path!",
845            ));
846        }
847
848        if path.to_str().is_none() {
849            return Err(Error::new(
850                ErrorKind::Other,
851                "--rustfmt-configuration-file contains non-valid UTF8 characters.",
852            ));
853        }
854
855        builder = builder.rustfmt_configuration_file(Some(path));
856    }
857
858    for regex in no_partialeq {
859        builder = builder.no_partialeq(regex);
860    }
861
862    for regex in no_copy {
863        builder = builder.no_copy(regex);
864    }
865
866    for regex in no_debug {
867        builder = builder.no_debug(regex);
868    }
869
870    for regex in no_default {
871        builder = builder.no_default(regex);
872    }
873
874    for regex in no_hash {
875        builder = builder.no_hash(regex);
876    }
877
878    for regex in must_use_type {
879        builder = builder.must_use_type(regex);
880    }
881
882    if let Some(dynamic_library_name) = dynamic_loading {
883        builder = builder.dynamic_library_name(dynamic_library_name);
884    }
885
886    if dynamic_link_require_all {
887        builder = builder.dynamic_link_require_all(true);
888    }
889
890    if respect_cxx_access_specs {
891        builder = builder.respect_cxx_access_specs(true);
892    }
893
894    if translate_enum_integer_types {
895        builder = builder.translate_enum_integer_types(true);
896    }
897
898    if c_naming {
899        builder = builder.c_naming(true);
900    }
901
902    if explicit_padding {
903        builder = builder.explicit_padding(true);
904    }
905
906    if vtable_generation {
907        builder = builder.vtable_generation(true);
908    }
909
910    if sort_semantically {
911        builder = builder.sort_semantically(true);
912    }
913
914    if merge_extern_blocks {
915        builder = builder.merge_extern_blocks(true);
916    }
917
918    for abi_override in override_abi {
919        let (regex, abi_str) = abi_override
920            .rsplit_once('=')
921            .expect("Invalid ABI override: Missing `=`");
922        let abi = abi_str
923            .parse()
924            .unwrap_or_else(|err| panic!("Invalid ABI override: {}", err));
925        builder = builder.override_abi(abi, regex);
926    }
927
928    if wrap_unsafe_ops {
929        builder = builder.wrap_unsafe_ops(true);
930    }
931
932    #[derive(Debug)]
933    struct CustomDeriveCallback {
934        derives: Vec<String>,
935        kind: Option<TypeKind>,
936        regex_set: bindgen::RegexSet,
937    }
938
939    impl bindgen::callbacks::ParseCallbacks for CustomDeriveCallback {
940        fn cli_args(&self) -> Vec<String> {
941            let mut args = vec![];
942
943            let flag = match &self.kind {
944                None => "--with-derive-custom",
945                Some(TypeKind::Struct) => "--with-derive-custom-struct",
946                Some(TypeKind::Enum) => "--with-derive-custom-enum",
947                Some(TypeKind::Union) => "--with-derive-custom-union",
948            };
949
950            let derives = self.derives.join(",");
951
952            for item in self.regex_set.get_items() {
953                args.extend_from_slice(&[
954                    flag.to_owned(),
955                    format!("{}={}", item, derives),
956                ]);
957            }
958
959            args
960        }
961
962        fn add_derives(
963            &self,
964            info: &bindgen::callbacks::DeriveInfo<'_>,
965        ) -> Vec<String> {
966            if self.kind.map(|kind| kind == info.kind).unwrap_or(true) &&
967                self.regex_set.matches(info.name)
968            {
969                return self.derives.clone();
970            }
971            vec![]
972        }
973    }
974
975    for (custom_derives, kind) in [
976        (with_derive_custom, None),
977        (with_derive_custom_struct, Some(TypeKind::Struct)),
978        (with_derive_custom_enum, Some(TypeKind::Enum)),
979        (with_derive_custom_union, Some(TypeKind::Union)),
980    ] {
981        for custom_derive in custom_derives {
982            let (regex, derives) = custom_derive
983                .rsplit_once('=')
984                .expect("Invalid custom derive argument: Missing `=`");
985            let derives = derives.split(',').map(|s| s.to_owned()).collect();
986
987            let mut regex_set = RegexSet::new();
988            regex_set.insert(regex);
989            regex_set.build(false);
990
991            builder = builder.parse_callbacks(Box::new(CustomDeriveCallback {
992                derives,
993                kind,
994                regex_set,
995            }));
996        }
997    }
998
999    if wrap_static_fns {
1000        builder = builder.wrap_static_fns(true);
1001    }
1002
1003    if let Some(path) = wrap_static_fns_path {
1004        builder = builder.wrap_static_fns_path(path);
1005    }
1006
1007    if let Some(suffix) = wrap_static_fns_suffix {
1008        builder = builder.wrap_static_fns_suffix(suffix);
1009    }
1010
1011    Ok((builder, output, verbose))
1012}
1013