@@ -182,6 +182,7 @@ impl From<DerivableTraits> for Vec<&'static str> {
182
182
}
183
183
}
184
184
185
+ #[ derive( Clone ) ]
185
186
struct CodegenResult < ' a > {
186
187
items : Vec < proc_macro2:: TokenStream > ,
187
188
@@ -435,6 +436,15 @@ impl CodeGenerator for Item {
435
436
return ;
436
437
}
437
438
439
+ if self . is_dynamic ( ctx) {
440
+ debug ! (
441
+ "Item is to be dynamically generated; ignoring it for now. \
442
+ self = {:?}",
443
+ self
444
+ ) ;
445
+ return ;
446
+ }
447
+
438
448
if self . is_blacklisted ( ctx) || result. seen ( self . id ( ) ) {
439
449
debug ! (
440
450
"<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \
@@ -3913,6 +3923,126 @@ impl CodeGenerator for ObjCInterface {
3913
3923
}
3914
3924
}
3915
3925
3926
+ trait DynamicBindingGenerator {
3927
+ /// Extra information from the caller.
3928
+ type Extra ;
3929
+
3930
+ fn dyngen < ' a > (
3931
+ & self ,
3932
+ ctx : & BindgenContext ,
3933
+ def_result : & mut CodegenResult < ' a > ,
3934
+ impl_result : & mut CodegenResult < ' a > ,
3935
+ extra : & Self :: Extra ,
3936
+ ) ;
3937
+ }
3938
+
3939
+ impl DynamicBindingGenerator for Item {
3940
+ type Extra = ( ) ;
3941
+
3942
+ fn dyngen < ' a > (
3943
+ & self ,
3944
+ ctx : & BindgenContext ,
3945
+ def_result : & mut CodegenResult < ' a > ,
3946
+ impl_result : & mut CodegenResult < ' a > ,
3947
+ _extra : & ( ) ,
3948
+ ) {
3949
+ assert ! ( self . is_dynamic( ctx) ) ;
3950
+ if !self . is_enabled_for_codegen ( ctx) {
3951
+ return ;
3952
+ }
3953
+
3954
+ // If this item is blacklisted, or we've already seen it, nothing to do.
3955
+ if self . is_blacklisted ( ctx) ||
3956
+ def_result. seen ( self . id ( ) ) ||
3957
+ impl_result. seen ( self . id ( ) )
3958
+ {
3959
+ debug ! (
3960
+ "<Item as DynamicBindingGenerator>::codegen: Ignoring hidden or seen: \
3961
+ self = {:?}",
3962
+ self
3963
+ ) ;
3964
+ return ;
3965
+ }
3966
+
3967
+ debug ! (
3968
+ "<Item as DynamicBindingGenerator>::dyngen: self = {:?}" ,
3969
+ self
3970
+ ) ;
3971
+
3972
+ if !ctx. codegen_items ( ) . contains ( & self . id ( ) ) {
3973
+ warn ! ( "Found non-whitelisted item in dynamic binding generation: {:?}" , self ) ;
3974
+ }
3975
+
3976
+ def_result. set_seen ( self . id ( ) ) ;
3977
+ impl_result. set_seen ( self . id ( ) ) ;
3978
+
3979
+ match * self . kind ( ) {
3980
+ ItemKind :: Function ( ref fun) => {
3981
+ assert ! ( fun. kind( ) == FunctionKind :: Function ) ;
3982
+ fun. dyngen ( ctx, def_result, impl_result, self ) ;
3983
+ }
3984
+ _ => panic ! (
3985
+ "Unexpected item type when doing dynamic bindings generation."
3986
+ ) ,
3987
+ }
3988
+ }
3989
+ }
3990
+
3991
+ impl DynamicBindingGenerator for Function {
3992
+ type Extra = Item ;
3993
+
3994
+ fn dyngen < ' a > (
3995
+ & self ,
3996
+ ctx : & BindgenContext ,
3997
+ def_result : & mut CodegenResult < ' a > ,
3998
+ impl_result : & mut CodegenResult < ' a > ,
3999
+ item : & Item ,
4000
+ ) {
4001
+ let signature_item = ctx. resolve_item ( self . signature ( ) ) ;
4002
+ let signature = signature_item. kind ( ) . expect_type ( ) . canonical_type ( ctx) ;
4003
+ let signature = match * signature. kind ( ) {
4004
+ TypeKind :: Function ( ref sig) => sig,
4005
+ _ => panic ! ( "Signature kind is not a Function: {:?}" , signature) ,
4006
+ } ;
4007
+
4008
+ let canonical_name = item. canonical_name ( ctx) ;
4009
+ let abi = match signature. abi ( ) {
4010
+ Abi :: ThisCall if !ctx. options ( ) . rust_features ( ) . thiscall_abi => {
4011
+ warn ! ( "Skipping function with thiscall ABI that isn't supported by the configured Rust target" ) ;
4012
+ return ;
4013
+ }
4014
+ Abi :: Win64 if signature. is_variadic ( ) => {
4015
+ warn ! ( "Skipping variadic function with Win64 ABI that isn't supported" ) ;
4016
+ return ;
4017
+ }
4018
+ Abi :: Unknown ( unknown_abi) => {
4019
+ panic ! (
4020
+ "Invalid or unknown abi {:?} for function {:?} ({:?})" ,
4021
+ unknown_abi, canonical_name, self
4022
+ ) ;
4023
+ }
4024
+ abi => abi,
4025
+ } ;
4026
+
4027
+ let args = utils:: fnsig_arguments ( ctx, signature) ;
4028
+ let args_identifiers =
4029
+ utils:: fnsig_argument_identifiers ( ctx, signature) ;
4030
+ let ret = utils:: fnsig_return_ty ( ctx, signature) ;
4031
+
4032
+ let ident = ctx. rust_ident ( & canonical_name) ;
4033
+
4034
+ def_result. push ( quote ! {
4035
+ #ident: unsafe extern #abi fn ( #( #args ) , * ) #ret,
4036
+ } ) ;
4037
+
4038
+ impl_result. push ( quote ! {
4039
+ pub unsafe extern #abi fn #ident ( & self , #( #args ) , * ) #ret {
4040
+ ( self . #ident) ( #( #args_identifiers ) , * )
4041
+ }
4042
+ } ) ;
4043
+ }
4044
+ }
4045
+
3916
4046
pub ( crate ) fn codegen (
3917
4047
context : BindgenContext ,
3918
4048
) -> ( Vec < proc_macro2:: TokenStream > , BindgenOptions ) {
@@ -3948,6 +4078,116 @@ pub(crate) fn codegen(
3948
4078
& ( ) ,
3949
4079
) ;
3950
4080
4081
+ // If the set of items to generate dynamic bindings for is nonempty...
4082
+ if !context. dyngen_items ( ) . is_empty ( ) {
4083
+ let _t = context. timer ( "dyngen" ) ;
4084
+ debug ! ( "dyngen: {:?}" , context. options( ) ) ;
4085
+
4086
+ // `def_result` tracks the tokens that will appears inside the library struct -- these
4087
+ // are the definitions of the symbols inside the library struct, e.g.:
4088
+ // ```
4089
+ // struct Lib {
4090
+ // __library: ::libloading::Library,
4091
+ // x: unsafe extern ..., // <- tracks these!
4092
+ // ...
4093
+ // }
4094
+ // ```
4095
+ //
4096
+ // `impl_result` tracks the tokens that will appear inside the call implementation,
4097
+ // e.g.:
4098
+ //
4099
+ // ```
4100
+ // impl Lib {
4101
+ // ...
4102
+ // pub unsafe extern "C" fn foo(&self, ...) { // <- tracks these!
4103
+ // (self.foo)(...)
4104
+ // }
4105
+ // }
4106
+ // ```
4107
+ //
4108
+ // We clone the CodeGenerator object used for normal code generation, but set its items
4109
+ // to the empty vector. We do this so that we can keep track of which items we have
4110
+ // seen, etc.
4111
+ let mut def_result = result. clone ( ) ;
4112
+ def_result. items = vec ! [ ] ;
4113
+ let mut impl_result = result. clone ( ) ;
4114
+ impl_result. items = vec ! [ ] ;
4115
+
4116
+ // Extern the libloading crate.
4117
+ result. push ( quote ! {
4118
+ extern crate libloading;
4119
+ } ) ;
4120
+
4121
+ // Run dynamic binding generation for each of the required items.
4122
+ for item in context. dyngen_items ( ) {
4123
+ context. resolve_item ( * item) . dyngen (
4124
+ context,
4125
+ & mut def_result,
4126
+ & mut impl_result,
4127
+ & ( ) ,
4128
+ ) ;
4129
+ }
4130
+
4131
+ let lib_ident = context. rust_ident (
4132
+ context. options ( ) . dynamic_library_name . as_ref ( ) . unwrap ( ) ,
4133
+ ) ;
4134
+
4135
+ let struct_items = def_result. items ;
4136
+ result. push ( quote ! {
4137
+ pub struct #lib_ident {
4138
+ __library: :: libloading:: Library ,
4139
+ #( #struct_items) *
4140
+ }
4141
+ } ) ;
4142
+
4143
+ let build_locals = context
4144
+ . dyngen_items ( )
4145
+ . iter ( )
4146
+ . map ( |& item| {
4147
+ let canonical_name = item. canonical_name ( context) ;
4148
+ let ident = context. rust_ident ( & canonical_name) ;
4149
+
4150
+ quote ! {
4151
+ let #ident = * __library. get( #canonical_name. as_bytes( ) ) ?;
4152
+ }
4153
+ } )
4154
+ . collect :: < Vec < _ > > ( ) ;
4155
+
4156
+ let init_fields = context
4157
+ . dyngen_items ( )
4158
+ . iter ( )
4159
+ . map ( |& item| {
4160
+ let canonical_name = item. canonical_name ( context) ;
4161
+ let ident = context. rust_ident ( & canonical_name) ;
4162
+
4163
+ quote ! {
4164
+ #ident
4165
+ }
4166
+ } )
4167
+ . collect :: < Vec < _ > > ( ) ;
4168
+
4169
+ let impl_items = impl_result. items ;
4170
+ result. push ( quote ! {
4171
+ impl #lib_ident {
4172
+ pub unsafe fn new<P >(
4173
+ path: P
4174
+ ) -> Result <Self , :: libloading:: Error >
4175
+ where P : AsRef <:: std:: ffi:: OsStr > {
4176
+ let __library = :: libloading:: Library :: new( path) ?;
4177
+ #( #build_locals ) *
4178
+ Ok (
4179
+ #lib_ident {
4180
+ __library: __library,
4181
+ #( #init_fields ) , *
4182
+ }
4183
+ )
4184
+ }
4185
+
4186
+ #( #impl_items ) *
4187
+ }
4188
+ } ) ;
4189
+ }
4190
+
3951
4191
result. items
3952
4192
} )
3953
4193
}
@@ -4356,6 +4596,35 @@ mod utils {
4356
4596
args
4357
4597
}
4358
4598
4599
+ pub fn fnsig_argument_identifiers (
4600
+ ctx : & BindgenContext ,
4601
+ sig : & FunctionSig ,
4602
+ ) -> Vec < proc_macro2:: TokenStream > {
4603
+ let mut unnamed_arguments = 0 ;
4604
+ let args = sig
4605
+ . argument_types ( )
4606
+ . iter ( )
4607
+ . map ( |& ( ref name, _ty) | {
4608
+ let arg_name = match * name {
4609
+ Some ( ref name) => ctx. rust_mangle ( name) . into_owned ( ) ,
4610
+ None => {
4611
+ unnamed_arguments += 1 ;
4612
+ format ! ( "arg{}" , unnamed_arguments)
4613
+ }
4614
+ } ;
4615
+
4616
+ assert ! ( !arg_name. is_empty( ) ) ;
4617
+ let arg_name = ctx. rust_ident ( arg_name) ;
4618
+
4619
+ quote ! {
4620
+ #arg_name
4621
+ }
4622
+ } )
4623
+ . collect :: < Vec < _ > > ( ) ;
4624
+
4625
+ args
4626
+ }
4627
+
4359
4628
pub fn fnsig_block (
4360
4629
ctx : & BindgenContext ,
4361
4630
sig : & FunctionSig ,
0 commit comments