11use bindgen:: callbacks:: TypeKind ;
22use bindgen:: {
3- builder, AliasVariation , Builder , CodegenConfig , EnumVariation ,
3+ builder, Abi , AliasVariation , Builder , CodegenConfig , EnumVariation ,
44 FieldVisibilityKind , Formatter , MacroTypeVariation , NonCopyUnionStyle ,
55 RegexSet , RustTarget , DEFAULT_ANON_FIELDS_PREFIX , RUST_TARGET_STRINGS ,
66} ;
7+ use clap:: error:: { Error , ErrorKind } ;
78use clap:: { CommandFactory , Parser } ;
89use std:: fs:: File ;
9- use std:: io:: { self , Error , ErrorKind } ;
10- use std:: path:: PathBuf ;
10+ use std:: io;
11+ use std:: path:: { Path , PathBuf } ;
1112use std:: process:: exit;
1213
1314fn rust_target_help ( ) -> String {
@@ -18,7 +19,9 @@ fn rust_target_help() -> String {
1819 )
1920}
2021
21- fn parse_codegen_config ( what_to_generate : & str ) -> io:: Result < CodegenConfig > {
22+ fn parse_codegen_config (
23+ what_to_generate : & str ,
24+ ) -> Result < CodegenConfig , Error > {
2225 let mut config = CodegenConfig :: empty ( ) ;
2326 for what in what_to_generate. split ( ',' ) {
2427 match what {
@@ -29,9 +32,9 @@ fn parse_codegen_config(what_to_generate: &str) -> io::Result<CodegenConfig> {
2932 "constructors" => config. insert ( CodegenConfig :: CONSTRUCTORS ) ,
3033 "destructors" => config. insert ( CodegenConfig :: DESTRUCTORS ) ,
3134 otherwise => {
32- return Err ( Error :: new (
33- ErrorKind :: Other ,
34- format ! ( "Unknown generate item: {}" , otherwise) ,
35+ return Err ( Error :: raw (
36+ ErrorKind :: InvalidValue ,
37+ format ! ( "Unknown codegen item kind : {}" , otherwise) ,
3538 ) ) ;
3639 }
3740 }
@@ -40,20 +43,64 @@ fn parse_codegen_config(what_to_generate: &str) -> io::Result<CodegenConfig> {
4043 Ok ( config)
4144}
4245
46+ fn parse_rustfmt_config_path ( path_str : & str ) -> Result < PathBuf , Error > {
47+ let path = Path :: new ( path_str) ;
48+
49+ if !path. is_absolute ( ) {
50+ return Err ( Error :: raw (
51+ ErrorKind :: InvalidValue ,
52+ "--rustfmt-configuration-file needs to be an absolute path!" ,
53+ ) ) ;
54+ }
55+
56+ if path. to_str ( ) . is_none ( ) {
57+ return Err ( Error :: raw (
58+ ErrorKind :: InvalidUtf8 ,
59+ "--rustfmt-configuration-file contains non-valid UTF8 characters." ,
60+ ) ) ;
61+ }
62+
63+ Ok ( path. to_path_buf ( ) )
64+ }
65+
66+ fn parse_abi_override ( abi_override : & str ) -> Result < ( Abi , String ) , Error > {
67+ let ( regex, abi_str) = abi_override
68+ . rsplit_once ( '=' )
69+ . ok_or_else ( || Error :: raw ( ErrorKind :: InvalidValue , "Missing `=`" ) ) ?;
70+
71+ let abi = abi_str
72+ . parse ( )
73+ . map_err ( |err| Error :: raw ( ErrorKind :: InvalidValue , err) ) ?;
74+
75+ Ok ( ( abi, regex. to_owned ( ) ) )
76+ }
77+
78+ fn parse_custom_derive (
79+ custom_derive : & str ,
80+ ) -> Result < ( Vec < String > , String ) , Error > {
81+ let ( regex, derives) = custom_derive
82+ . rsplit_once ( '=' )
83+ . ok_or_else ( || Error :: raw ( ErrorKind :: InvalidValue , "Missing `=`" ) ) ?;
84+
85+ let derives = derives. split ( ',' ) . map ( |s| s. to_owned ( ) ) . collect ( ) ;
86+
87+ Ok ( ( derives, regex. to_owned ( ) ) )
88+ }
89+
4390#[ derive( Parser , Debug ) ]
4491#[ clap(
4592 about = "Generates Rust bindings from C/C++ headers." ,
46- override_usage = "bindgen [ FLAGS] [ OPTIONS] [ HEADER] -- [ CLANG_ARGS] ..." ,
93+ override_usage = "bindgen < FLAGS> < OPTIONS> < HEADER> -- < CLANG_ARGS> ..." ,
4794 trailing_var_arg = true
4895) ]
4996struct BindgenCommand {
5097 /// C or C++ header file.
51- header : Option < String > ,
98+ header : String ,
5299 /// Path to write depfile to.
53100 #[ arg( long) ]
54101 depfile : Option < String > ,
55- /// The default style of code used to generate enums.
56- #[ arg( long, value_name = "VARIANT " ) ]
102+ /// The default STYLE of code used to generate enums.
103+ #[ arg( long, value_name = "STYLE " ) ]
57104 default_enum_style : Option < EnumVariation > ,
58105 /// Mark any enum whose name matches REGEX as a set of bitfield flags.
59106 #[ arg( long, value_name = "REGEX" ) ]
@@ -73,11 +120,11 @@ struct BindgenCommand {
73120 /// Mark any enum whose name matches REGEX as a module of constants.
74121 #[ arg( long, value_name = "REGEX" ) ]
75122 constified_enum_module : Vec < String > ,
76- /// The default signed/unsigned type for C macro constants.
77- #[ arg( long, value_name = "VARIANT " ) ]
123+ /// The default signed/unsigned TYPE for C macro constants.
124+ #[ arg( long, value_name = "TYPE " ) ]
78125 default_macro_constant_type : Option < MacroTypeVariation > ,
79- /// The default style of code used to generate typedefs.
80- #[ arg( long, value_name = "VARIANT " ) ]
126+ /// The default STYLE of code used to generate typedefs.
127+ #[ arg( long, value_name = "STYLE " ) ]
81128 default_alias_style : Option < AliasVariation > ,
82129 /// Mark any typedef alias whose name matches REGEX to use normal type aliasing.
83130 #[ arg( long, value_name = "REGEX" ) ]
@@ -88,7 +135,7 @@ struct BindgenCommand {
88135 /// Mark any typedef alias whose name matches REGEX to have a new type with Deref and DerefMut to the inner type.
89136 #[ arg( long, value_name = "REGEX" ) ]
90137 new_type_alias_deref : Vec < String > ,
91- /// The default style of code used to generate unions with non-Copy members. Note that ManuallyDrop was first stabilized in Rust 1.20.0.
138+ /// The default STYLE of code used to generate unions with non-Copy members. Note that ManuallyDrop was first stabilized in Rust 1.20.0.
92139 #[ arg( long, value_name = "STYLE" ) ]
93140 default_non_copy_union_style : Option < NonCopyUnionStyle > ,
94141 /// Mark any union whose name matches REGEX and who has a non-Copy member to use a bindgen-generated wrapper for fields.
@@ -169,10 +216,10 @@ struct BindgenCommand {
169216 /// Output bindings for builtin definitions, e.g. __builtin_va_list.
170217 #[ arg( long) ]
171218 builtins : bool ,
172- /// Use the given prefix before raw types instead of ::std::os::raw.
219+ /// Use the given PREFIX before raw types instead of ::std::os::raw.
173220 #[ arg( long, value_name = "PREFIX" ) ]
174221 ctypes_prefix : Option < String > ,
175- /// Use the given prefix for anonymous fields.
222+ /// Use the given PREFIX for anonymous fields.
176223 #[ arg( long, default_value = DEFAULT_ANON_FIELDS_PREFIX , value_name = "PREFIX" ) ]
177224 anon_fields_prefix : String ,
178225 /// Time the different bindgen phases and print to stderr
@@ -184,7 +231,7 @@ struct BindgenCommand {
184231 /// Output our internal IR for debugging purposes.
185232 #[ arg( long) ]
186233 emit_ir : bool ,
187- /// Dump graphviz dot file.
234+ /// Dump a graphviz dot file to PATH .
188235 #[ arg( long, value_name = "PATH" ) ]
189236 emit_ir_graphviz : Option < String > ,
190237 /// Enable support for C++ namespaces.
@@ -232,8 +279,8 @@ struct BindgenCommand {
232279 /// Add a raw line of Rust code at the beginning of output.
233280 #[ arg( long) ]
234281 raw_line : Vec < String > ,
235- /// Add a raw line of Rust code to a given module.
236- #[ arg( long, number_of_values = 2 , value_names = [ "MODULE-NAME " , "RAW-LINE " ] ) ]
282+ /// Add a RAW_LINE of Rust code to a given module with name MODULE_NAME .
283+ #[ arg( long, number_of_values = 2 , value_names = [ "MODULE_NAME " , "RAW_LINE " ] ) ]
237284 module_raw_line : Vec < String > ,
238285 #[ arg( long, help = rust_target_help( ) ) ]
239286 rust_target : Option < RustTarget > ,
@@ -277,16 +324,16 @@ struct BindgenCommand {
277324 /// `--formatter=none` instead.
278325 #[ arg( long) ]
279326 no_rustfmt_bindings : bool ,
280- /// Which tool should be used to format the bindings
327+ /// Which FORMATTER should be used for the bindings
281328 #[ arg(
282329 long,
283330 value_name = "FORMATTER" ,
284331 conflicts_with = "no_rustfmt_bindings"
285332 ) ]
286333 formatter : Option < Formatter > ,
287- /// The absolute path to the rustfmt configuration file. The configuration file will be used for formatting the bindings. This parameter sets `formatter` to `rustfmt`.
288- #[ arg( long, value_name = "PATH" , conflicts_with = "no_rustfmt_bindings" ) ]
289- rustfmt_configuration_file : Option < String > ,
334+ /// The absolute PATH to the rustfmt configuration file. The configuration file will be used for formatting the bindings. This parameter sets `formatter` to `rustfmt`.
335+ #[ arg( long, value_name = "PATH" , conflicts_with = "no_rustfmt_bindings" , value_parser=parse_rustfmt_config_path ) ]
336+ rustfmt_configuration_file : Option < PathBuf > ,
290337 /// Avoid deriving PartialEq for types matching REGEX.
291338 #[ arg( long, value_name = "REGEX" ) ]
292339 no_partialeq : Vec < String > ,
@@ -311,10 +358,10 @@ struct BindgenCommand {
311358 /// Use `*const [T; size]` instead of `*const T` for C arrays
312359 #[ arg( long) ]
313360 use_array_pointers_in_arguments : bool ,
314- /// The name to be used in a #[link(wasm_import_module = ...)] statement
361+ /// The NAME to be used in a #[link(wasm_import_module = ...)] statement
315362 #[ arg( long, value_name = "NAME" ) ]
316363 wasm_import_module_name : Option < String > ,
317- /// Use dynamic loading mode with the given library name .
364+ /// Use dynamic loading mode with the given library NAME .
318365 #[ arg( long, value_name = "NAME" ) ]
319366 dynamic_loading : Option < String > ,
320367 /// Require successful linkage to all functions in the library.
@@ -344,36 +391,36 @@ struct BindgenCommand {
344391 /// Deduplicates extern blocks.
345392 #[ arg( long) ]
346393 merge_extern_blocks : bool ,
347- /// 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, efiapi, fastcall, thiscall, aapcs, win64 or C-unwind.
348- #[ arg( long, value_name = "OVERRIDE" ) ]
349- override_abi : Vec < String > ,
394+ /// 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, efiapi, fastcall, thiscall, aapcs, win64 or C-unwind<.>
395+ #[ arg( long, value_name = "OVERRIDE" , value_parser = parse_abi_override ) ]
396+ override_abi : Vec < ( Abi , String ) > ,
350397 /// Wrap unsafe operations in unsafe blocks.
351398 #[ arg( long) ]
352399 wrap_unsafe_ops : bool ,
353400 /// 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.
354- #[ arg( long, value_name = "CUSTOM" ) ]
355- with_derive_custom : Vec < String > ,
401+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_derive ) ]
402+ with_derive_custom : Vec < ( Vec < String > , String ) > ,
356403 /// 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.
357- #[ arg( long, value_name = "CUSTOM" ) ]
358- with_derive_custom_struct : Vec < String > ,
404+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_derive ) ]
405+ with_derive_custom_struct : Vec < ( Vec < String > , String ) > ,
359406 /// 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.
360- #[ arg( long, value_name = "CUSTOM" ) ]
361- with_derive_custom_enum : Vec < String > ,
407+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_derive ) ]
408+ with_derive_custom_enum : Vec < ( Vec < String > , String ) > ,
362409 /// 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.
363- #[ arg( long, value_name = "CUSTOM" ) ]
364- with_derive_custom_union : Vec < String > ,
410+ #[ arg( long, value_name = "CUSTOM" , value_parser = parse_custom_derive ) ]
411+ with_derive_custom_union : Vec < ( Vec < String > , String ) > ,
365412 /// Generate wrappers for `static` and `static inline` functions.
366413 #[ arg( long, requires = "experimental" ) ]
367414 wrap_static_fns : bool ,
368- /// Sets the path for the source file that must be created due to the presence of `static` and
415+ /// Sets the PATH for the source file that must be created due to the presence of `static` and
369416 /// `static inline` functions.
370417 #[ arg( long, requires = "experimental" , value_name = "PATH" ) ]
371418 wrap_static_fns_path : Option < PathBuf > ,
372- /// Sets the suffix added to the extern wrapper functions generated for `static` and `static
419+ /// Sets the SUFFIX added to the extern wrapper functions generated for `static` and `static
373420 /// inline` functions.
374421 #[ arg( long, requires = "experimental" , value_name = "SUFFIX" ) ]
375422 wrap_static_fns_suffix : Option < String > ,
376- /// Set the default visibility of fields, including bitfields and accessor methods for
423+ /// Set the default VISIBILITY of fields, including bitfields and accessor methods for
377424 /// bitfields. This flag is ignored if the `--respect-cxx-access-specs` flag is used.
378425 #[ arg( long, value_name = "VISIBILITY" ) ]
379426 default_visibility : Option < FieldVisibilityKind > ,
@@ -542,11 +589,7 @@ where
542589
543590 let mut builder = builder ( ) ;
544591
545- if let Some ( header) = header {
546- builder = builder. header ( header) ;
547- } else {
548- return Err ( Error :: new ( ErrorKind :: Other , "Header not found" ) ) ;
549- }
592+ builder = builder. header ( header) ;
550593
551594 if let Some ( rust_target) = rust_target {
552595 builder = builder. rust_target ( rust_target) ;
@@ -874,23 +917,7 @@ where
874917 builder = builder. formatter ( formatter) ;
875918 }
876919
877- if let Some ( path_str) = rustfmt_configuration_file {
878- let path = PathBuf :: from ( path_str) ;
879-
880- if !path. is_absolute ( ) {
881- return Err ( Error :: new (
882- ErrorKind :: Other ,
883- "--rustfmt-configuration-file needs to be an absolute path!" ,
884- ) ) ;
885- }
886-
887- if path. to_str ( ) . is_none ( ) {
888- return Err ( Error :: new (
889- ErrorKind :: Other ,
890- "--rustfmt-configuration-file contains non-valid UTF8 characters." ,
891- ) ) ;
892- }
893-
920+ if let Some ( path) = rustfmt_configuration_file {
894921 builder = builder. rustfmt_configuration_file ( Some ( path) ) ;
895922 }
896923
@@ -976,13 +1003,7 @@ where
9761003 builder = builder. merge_extern_blocks ( true ) ;
9771004 }
9781005
979- for abi_override in override_abi {
980- let ( regex, abi_str) = abi_override
981- . rsplit_once ( '=' )
982- . expect ( "Invalid ABI override: Missing `=`" ) ;
983- let abi = abi_str
984- . parse ( )
985- . unwrap_or_else ( |err| panic ! ( "Invalid ABI override: {}" , err) ) ;
1006+ for ( abi, regex) in override_abi {
9861007 builder = builder. override_abi ( abi, regex) ;
9871008 }
9881009
@@ -1052,12 +1073,7 @@ where
10521073 ) ,
10531074 ] {
10541075 let name = emit_diagnostics. then_some ( name) ;
1055- for custom_derive in custom_derives {
1056- let ( regex, derives) = custom_derive
1057- . rsplit_once ( '=' )
1058- . expect ( "Invalid custom derive argument: Missing `=`" ) ;
1059- let derives = derives. split ( ',' ) . map ( |s| s. to_owned ( ) ) . collect ( ) ;
1060-
1076+ for ( derives, regex) in custom_derives {
10611077 let mut regex_set = RegexSet :: new ( ) ;
10621078 regex_set. insert ( regex) ;
10631079 regex_set. build_with_diagnostics ( false , name) ;
0 commit comments