@@ -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,122 @@ 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
+ struct_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
+ struct_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
+ struct_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
+ struct_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, struct_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
+ struct_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 ret = utils:: fnsig_return_ty ( ctx, signature) ;
4029
+
4030
+ let ident = ctx. rust_ident ( & canonical_name) ;
4031
+
4032
+ struct_result. push ( quote ! {
4033
+ #ident: libloading:: Symbol <' a, unsafe extern #abi fn ( #( #args ) , * ) #ret>,
4034
+ } ) ;
4035
+
4036
+ impl_result. push ( quote ! {
4037
+ #ident: lib. get( #canonical_name. as_bytes( ) ) . unwrap( ) ,
4038
+ } ) ;
4039
+ }
4040
+ }
4041
+
3916
4042
pub ( crate ) fn codegen (
3917
4043
context : BindgenContext ,
3918
4044
) -> ( Vec < proc_macro2:: TokenStream > , BindgenOptions ) {
@@ -3948,6 +4074,75 @@ pub(crate) fn codegen(
3948
4074
& ( ) ,
3949
4075
) ;
3950
4076
4077
+ // If the set of items to generate dynamic bindings for is nonempty...
4078
+ if !context. dyngen_items ( ) . is_empty ( ) {
4079
+ let _t = context. timer ( "dyngen" ) ;
4080
+ debug ! ( "dyngen: {:?}" , context. options( ) ) ;
4081
+
4082
+ // `struct_result` tracks the tokens that will appears inside the library struct, e.g.:
4083
+ // ```
4084
+ // struct Lib {
4085
+ // x: libloading::Symbol<'a, ...>, // <- tracks these!
4086
+ // }
4087
+ // ```
4088
+ //
4089
+ // `impl_result` tracks the tokens that will appear inside the library struct's
4090
+ // implementation, e.g.:
4091
+ //
4092
+ // ```
4093
+ // impl<'a> Lib<'a> {
4094
+ // pub fn new(lib: &libloading::Library) -> Lib {
4095
+ // unsafe {
4096
+ // x: lib.get(...), // <- tracks these!
4097
+ // }
4098
+ // }
4099
+ // }
4100
+ // ```
4101
+ //
4102
+ // We clone the CodeGenerator object used for normal code generation, but set its items
4103
+ // to the empty vector. We do this so that we can keep track of which items we have
4104
+ // seen, etc.
4105
+ let mut struct_result = result. clone ( ) ;
4106
+ struct_result. items = vec ! [ ] ;
4107
+ let mut impl_result = result. clone ( ) ;
4108
+ impl_result. items = vec ! [ ] ;
4109
+
4110
+ // Run dynamic binding generation for each of the required items.
4111
+ for item in context. dyngen_items ( ) {
4112
+ context. resolve_item ( * item) . dyngen (
4113
+ context,
4114
+ & mut struct_result,
4115
+ & mut impl_result,
4116
+ & ( ) ,
4117
+ ) ;
4118
+ }
4119
+
4120
+ let lib_ident = context. rust_ident (
4121
+ context. options ( ) . dynamic_library_name . as_ref ( ) . unwrap ( ) ,
4122
+ ) ;
4123
+
4124
+ let struct_items = struct_result. items ;
4125
+ result. push ( quote ! {
4126
+ extern crate libloading;
4127
+ pub struct #lib_ident<' a> {
4128
+ #( #struct_items) *
4129
+ }
4130
+ } ) ;
4131
+
4132
+ let impl_items = impl_result. items ;
4133
+ result. push ( quote ! {
4134
+ impl <' a> #lib_ident<' a> {
4135
+ pub fn new( lib: & libloading:: Library ) -> #lib_ident {
4136
+ unsafe {
4137
+ #lib_ident {
4138
+ #( #impl_items) *
4139
+ }
4140
+ }
4141
+ }
4142
+ }
4143
+ } ) ;
4144
+ }
4145
+
3951
4146
result. items
3952
4147
} )
3953
4148
}
0 commit comments