1
1
use bindgen:: callbacks:: TypeKind ;
2
2
use bindgen:: {
3
- builder, AliasVariation , Builder , CodegenConfig , EnumVariation ,
3
+ builder, Abi , AliasVariation , Builder , CodegenConfig , EnumVariation ,
4
4
FieldVisibilityKind , Formatter , MacroTypeVariation , NonCopyUnionStyle ,
5
5
RegexSet , RustTarget , DEFAULT_ANON_FIELDS_PREFIX , RUST_TARGET_STRINGS ,
6
6
} ;
7
+ use clap:: error:: { Error , ErrorKind } ;
7
8
use clap:: { CommandFactory , Parser } ;
8
9
use 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 } ;
11
12
use std:: process:: exit;
12
13
13
14
fn rust_target_help ( ) -> String {
@@ -18,7 +19,9 @@ fn rust_target_help() -> String {
18
19
)
19
20
}
20
21
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 > {
22
25
let mut config = CodegenConfig :: empty ( ) ;
23
26
for what in what_to_generate. split ( ',' ) {
24
27
match what {
@@ -29,9 +32,9 @@ fn parse_codegen_config(what_to_generate: &str) -> io::Result<CodegenConfig> {
29
32
"constructors" => config. insert ( CodegenConfig :: CONSTRUCTORS ) ,
30
33
"destructors" => config. insert ( CodegenConfig :: DESTRUCTORS ) ,
31
34
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) ,
35
38
) ) ;
36
39
}
37
40
}
@@ -40,20 +43,64 @@ fn parse_codegen_config(what_to_generate: &str) -> io::Result<CodegenConfig> {
40
43
Ok ( config)
41
44
}
42
45
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
+
43
90
#[ derive( Parser , Debug ) ]
44
91
#[ clap(
45
92
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> ..." ,
47
94
trailing_var_arg = true
48
95
) ]
49
96
struct BindgenCommand {
50
97
/// C or C++ header file.
51
- header : Option < String > ,
98
+ header : String ,
52
99
/// Path to write depfile to.
53
100
#[ arg( long) ]
54
101
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 " ) ]
57
104
default_enum_style : Option < EnumVariation > ,
58
105
/// Mark any enum whose name matches REGEX as a set of bitfield flags.
59
106
#[ arg( long, value_name = "REGEX" ) ]
@@ -73,11 +120,11 @@ struct BindgenCommand {
73
120
/// Mark any enum whose name matches REGEX as a module of constants.
74
121
#[ arg( long, value_name = "REGEX" ) ]
75
122
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 " ) ]
78
125
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 " ) ]
81
128
default_alias_style : Option < AliasVariation > ,
82
129
/// Mark any typedef alias whose name matches REGEX to use normal type aliasing.
83
130
#[ arg( long, value_name = "REGEX" ) ]
@@ -88,7 +135,7 @@ struct BindgenCommand {
88
135
/// Mark any typedef alias whose name matches REGEX to have a new type with Deref and DerefMut to the inner type.
89
136
#[ arg( long, value_name = "REGEX" ) ]
90
137
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.
92
139
#[ arg( long, value_name = "STYLE" ) ]
93
140
default_non_copy_union_style : Option < NonCopyUnionStyle > ,
94
141
/// 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 {
169
216
/// Output bindings for builtin definitions, e.g. __builtin_va_list.
170
217
#[ arg( long) ]
171
218
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.
173
220
#[ arg( long, value_name = "PREFIX" ) ]
174
221
ctypes_prefix : Option < String > ,
175
- /// Use the given prefix for anonymous fields.
222
+ /// Use the given PREFIX for anonymous fields.
176
223
#[ arg( long, default_value = DEFAULT_ANON_FIELDS_PREFIX , value_name = "PREFIX" ) ]
177
224
anon_fields_prefix : String ,
178
225
/// Time the different bindgen phases and print to stderr
@@ -184,7 +231,7 @@ struct BindgenCommand {
184
231
/// Output our internal IR for debugging purposes.
185
232
#[ arg( long) ]
186
233
emit_ir : bool ,
187
- /// Dump graphviz dot file.
234
+ /// Dump a graphviz dot file to PATH .
188
235
#[ arg( long, value_name = "PATH" ) ]
189
236
emit_ir_graphviz : Option < String > ,
190
237
/// Enable support for C++ namespaces.
@@ -232,8 +279,8 @@ struct BindgenCommand {
232
279
/// Add a raw line of Rust code at the beginning of output.
233
280
#[ arg( long) ]
234
281
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 " ] ) ]
237
284
module_raw_line : Vec < String > ,
238
285
#[ arg( long, help = rust_target_help( ) ) ]
239
286
rust_target : Option < RustTarget > ,
@@ -277,16 +324,16 @@ struct BindgenCommand {
277
324
/// `--formatter=none` instead.
278
325
#[ arg( long) ]
279
326
no_rustfmt_bindings : bool ,
280
- /// Which tool should be used to format the bindings
327
+ /// Which FORMATTER should be used for the bindings
281
328
#[ arg(
282
329
long,
283
330
value_name = "FORMATTER" ,
284
331
conflicts_with = "no_rustfmt_bindings"
285
332
) ]
286
333
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 > ,
290
337
/// Avoid deriving PartialEq for types matching REGEX.
291
338
#[ arg( long, value_name = "REGEX" ) ]
292
339
no_partialeq : Vec < String > ,
@@ -311,10 +358,10 @@ struct BindgenCommand {
311
358
/// Use `*const [T; size]` instead of `*const T` for C arrays
312
359
#[ arg( long) ]
313
360
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
315
362
#[ arg( long, value_name = "NAME" ) ]
316
363
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 .
318
365
#[ arg( long, value_name = "NAME" ) ]
319
366
dynamic_loading : Option < String > ,
320
367
/// Require successful linkage to all functions in the library.
@@ -344,36 +391,36 @@ struct BindgenCommand {
344
391
/// Deduplicates extern blocks.
345
392
#[ arg( long) ]
346
393
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 ) > ,
350
397
/// Wrap unsafe operations in unsafe blocks.
351
398
#[ arg( long) ]
352
399
wrap_unsafe_ops : bool ,
353
400
/// 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 ) > ,
356
403
/// 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 ) > ,
359
406
/// 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 ) > ,
362
409
/// 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 ) > ,
365
412
/// Generate wrappers for `static` and `static inline` functions.
366
413
#[ arg( long, requires = "experimental" ) ]
367
414
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
369
416
/// `static inline` functions.
370
417
#[ arg( long, requires = "experimental" , value_name = "PATH" ) ]
371
418
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
373
420
/// inline` functions.
374
421
#[ arg( long, requires = "experimental" , value_name = "SUFFIX" ) ]
375
422
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
377
424
/// bitfields. This flag is ignored if the `--respect-cxx-access-specs` flag is used.
378
425
#[ arg( long, value_name = "VISIBILITY" ) ]
379
426
default_visibility : Option < FieldVisibilityKind > ,
@@ -542,11 +589,7 @@ where
542
589
543
590
let mut builder = builder ( ) ;
544
591
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) ;
550
593
551
594
if let Some ( rust_target) = rust_target {
552
595
builder = builder. rust_target ( rust_target) ;
@@ -874,23 +917,7 @@ where
874
917
builder = builder. formatter ( formatter) ;
875
918
}
876
919
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 {
894
921
builder = builder. rustfmt_configuration_file ( Some ( path) ) ;
895
922
}
896
923
@@ -976,13 +1003,7 @@ where
976
1003
builder = builder. merge_extern_blocks ( true ) ;
977
1004
}
978
1005
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 {
986
1007
builder = builder. override_abi ( abi, regex) ;
987
1008
}
988
1009
@@ -1052,12 +1073,7 @@ where
1052
1073
) ,
1053
1074
] {
1054
1075
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 {
1061
1077
let mut regex_set = RegexSet :: new ( ) ;
1062
1078
regex_set. insert ( regex) ;
1063
1079
regex_set. build_with_diagnostics ( false , name) ;
0 commit comments