@@ -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,111 @@ 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
+ // Run dynamic binding generation for each of the required items.
4117
+ for item in context. dyngen_items ( ) {
4118
+ context. resolve_item ( * item) . dyngen (
4119
+ context,
4120
+ & mut def_result,
4121
+ & mut impl_result,
4122
+ & ( ) ,
4123
+ ) ;
4124
+ }
4125
+
4126
+ let lib_ident = context. rust_ident (
4127
+ context. options ( ) . dynamic_library_name . as_ref ( ) . unwrap ( ) ,
4128
+ ) ;
4129
+
4130
+ let struct_items = def_result. items ;
4131
+ result. push ( quote ! {
4132
+ pub struct #lib_ident {
4133
+ __library: :: libloading:: Library ,
4134
+ #( #struct_items) *
4135
+ }
4136
+ } ) ;
4137
+
4138
+ let build_locals = context
4139
+ . dyngen_items ( )
4140
+ . iter ( )
4141
+ . map ( |& item| {
4142
+ let canonical_name = item. canonical_name ( context) ;
4143
+ let ident = context. rust_ident ( & canonical_name) ;
4144
+
4145
+ quote ! {
4146
+ let #ident = * __library. get( #canonical_name. as_bytes( ) ) ?;
4147
+ }
4148
+ } )
4149
+ . collect :: < Vec < _ > > ( ) ;
4150
+
4151
+ let init_fields = context
4152
+ . dyngen_items ( )
4153
+ . iter ( )
4154
+ . map ( |& item| {
4155
+ let canonical_name = item. canonical_name ( context) ;
4156
+ let ident = context. rust_ident ( & canonical_name) ;
4157
+
4158
+ quote ! {
4159
+ #ident
4160
+ }
4161
+ } )
4162
+ . collect :: < Vec < _ > > ( ) ;
4163
+
4164
+ let impl_items = impl_result. items ;
4165
+ result. push ( quote ! {
4166
+ impl #lib_ident {
4167
+ pub unsafe fn new<P >(
4168
+ path: P
4169
+ ) -> Result <Self , :: libloading:: Error >
4170
+ where P : AsRef <:: std:: ffi:: OsStr > {
4171
+ let __library = :: libloading:: Library :: new( path) ?;
4172
+ #( #build_locals ) *
4173
+ Ok (
4174
+ #lib_ident {
4175
+ __library: __library,
4176
+ #( #init_fields ) , *
4177
+ }
4178
+ )
4179
+ }
4180
+
4181
+ #( #impl_items ) *
4182
+ }
4183
+ } ) ;
4184
+ }
4185
+
3951
4186
result. items
3952
4187
} )
3953
4188
}
@@ -4356,6 +4591,35 @@ mod utils {
4356
4591
args
4357
4592
}
4358
4593
4594
+ pub fn fnsig_argument_identifiers (
4595
+ ctx : & BindgenContext ,
4596
+ sig : & FunctionSig ,
4597
+ ) -> Vec < proc_macro2:: TokenStream > {
4598
+ let mut unnamed_arguments = 0 ;
4599
+ let args = sig
4600
+ . argument_types ( )
4601
+ . iter ( )
4602
+ . map ( |& ( ref name, _ty) | {
4603
+ let arg_name = match * name {
4604
+ Some ( ref name) => ctx. rust_mangle ( name) . into_owned ( ) ,
4605
+ None => {
4606
+ unnamed_arguments += 1 ;
4607
+ format ! ( "arg{}" , unnamed_arguments)
4608
+ }
4609
+ } ;
4610
+
4611
+ assert ! ( !arg_name. is_empty( ) ) ;
4612
+ let arg_name = ctx. rust_ident ( arg_name) ;
4613
+
4614
+ quote ! {
4615
+ #arg_name
4616
+ }
4617
+ } )
4618
+ . collect :: < Vec < _ > > ( ) ;
4619
+
4620
+ args
4621
+ }
4622
+
4359
4623
pub fn fnsig_block (
4360
4624
ctx : & BindgenContext ,
4361
4625
sig : & FunctionSig ,
0 commit comments