From 9eb512e27168d406e5a0dc406cc8f8b706fdf0c6 Mon Sep 17 00:00:00 2001 From: discord9 Date: Tue, 23 Apr 2024 15:31:32 +0800 Subject: [PATCH] feat: add dynamic loading of variable --- .../dynamic_loading_variable_required.rs | 32 +++++++++++++ .../tests/dynamic_loading_variable_simple.rs | 32 +++++++++++++ ...dynamic_loading_variable_with_allowlist.rs | 30 ++++++++++++ .../dynamic_loading_variable_required.h | 4 ++ .../headers/dynamic_loading_variable_simple.h | 4 ++ ...ynamic_loading_variable_with_allowlist.hpp | 5 ++ bindgen/codegen/dyngen.rs | 47 ++++++++++++++++++- bindgen/codegen/mod.rs | 16 +++++-- 8 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 bindgen-tests/tests/expectations/tests/dynamic_loading_variable_required.rs create mode 100644 bindgen-tests/tests/expectations/tests/dynamic_loading_variable_simple.rs create mode 100644 bindgen-tests/tests/expectations/tests/dynamic_loading_variable_with_allowlist.rs create mode 100644 bindgen-tests/tests/headers/dynamic_loading_variable_required.h create mode 100644 bindgen-tests/tests/headers/dynamic_loading_variable_simple.h create mode 100644 bindgen-tests/tests/headers/dynamic_loading_variable_with_allowlist.hpp diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_required.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_required.rs new file mode 100644 index 0000000000..a96efbe546 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_required.rs @@ -0,0 +1,32 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub struct TestLib { + __library: ::libloading::Library, + pub foo: *mut ::std::os::raw::c_int, + pub baz: *mut *mut ::std::os::raw::c_int, +} +impl TestLib { + pub unsafe fn new

(path: P) -> Result + where + P: AsRef<::std::ffi::OsStr>, + { + let library = ::libloading::Library::new(path)?; + Self::from_library(library) + } + pub unsafe fn from_library(library: L) -> Result + where + L: Into<::libloading::Library>, + { + let __library = library.into(); + let foo = __library.get::<*mut ::std::os::raw::c_int>(b"foo\0").map(|sym| *sym)?; + let baz = __library + .get::<*mut *mut ::std::os::raw::c_int>(b"baz\0") + .map(|sym| *sym)?; + Ok(TestLib { __library, foo, baz }) + } + pub unsafe fn foo(&self) -> *mut ::std::os::raw::c_int { + self.foo + } + pub unsafe fn baz(&self) -> *mut *mut ::std::os::raw::c_int { + self.baz + } +} diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_simple.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_simple.rs new file mode 100644 index 0000000000..ced70dbdba --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_simple.rs @@ -0,0 +1,32 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub struct TestLib { + __library: ::libloading::Library, + pub foo: Result<*mut ::std::os::raw::c_int, ::libloading::Error>, + pub baz: Result<*mut *mut ::std::os::raw::c_int, ::libloading::Error>, +} +impl TestLib { + pub unsafe fn new

(path: P) -> Result + where + P: AsRef<::std::ffi::OsStr>, + { + let library = ::libloading::Library::new(path)?; + Self::from_library(library) + } + pub unsafe fn from_library(library: L) -> Result + where + L: Into<::libloading::Library>, + { + let __library = library.into(); + let foo = __library.get::<*mut ::std::os::raw::c_int>(b"foo\0").map(|sym| *sym); + let baz = __library + .get::<*mut *mut ::std::os::raw::c_int>(b"baz\0") + .map(|sym| *sym); + Ok(TestLib { __library, foo, baz }) + } + pub unsafe fn foo(&self) -> *mut ::std::os::raw::c_int { + *self.foo.as_ref().expect("Expected variable, got error.") + } + pub unsafe fn baz(&self) -> *mut *mut ::std::os::raw::c_int { + *self.baz.as_ref().expect("Expected variable, got error.") + } +} diff --git a/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_with_allowlist.rs b/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_with_allowlist.rs new file mode 100644 index 0000000000..3f29e73814 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/dynamic_loading_variable_with_allowlist.rs @@ -0,0 +1,30 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub struct TestLib { + __library: ::libloading::Library, + pub foo: Result<*mut ::std::os::raw::c_int, ::libloading::Error>, + pub bar: Result<*mut ::std::os::raw::c_int, ::libloading::Error>, +} +impl TestLib { + pub unsafe fn new

(path: P) -> Result + where + P: AsRef<::std::ffi::OsStr>, + { + let library = ::libloading::Library::new(path)?; + Self::from_library(library) + } + pub unsafe fn from_library(library: L) -> Result + where + L: Into<::libloading::Library>, + { + let __library = library.into(); + let foo = __library.get::<*mut ::std::os::raw::c_int>(b"foo\0").map(|sym| *sym); + let bar = __library.get::<*mut ::std::os::raw::c_int>(b"bar\0").map(|sym| *sym); + Ok(TestLib { __library, foo, bar }) + } + pub unsafe fn foo(&self) -> *mut ::std::os::raw::c_int { + *self.foo.as_ref().expect("Expected variable, got error.") + } + pub unsafe fn bar(&self) -> *mut ::std::os::raw::c_int { + *self.bar.as_ref().expect("Expected variable, got error.") + } +} diff --git a/bindgen-tests/tests/headers/dynamic_loading_variable_required.h b/bindgen-tests/tests/headers/dynamic_loading_variable_required.h new file mode 100644 index 0000000000..8e811bb320 --- /dev/null +++ b/bindgen-tests/tests/headers/dynamic_loading_variable_required.h @@ -0,0 +1,4 @@ +// bindgen-flags: --dynamic-loading TestLib --dynamic-link-require-all + +int foo; +int *baz; \ No newline at end of file diff --git a/bindgen-tests/tests/headers/dynamic_loading_variable_simple.h b/bindgen-tests/tests/headers/dynamic_loading_variable_simple.h new file mode 100644 index 0000000000..5ecad752ed --- /dev/null +++ b/bindgen-tests/tests/headers/dynamic_loading_variable_simple.h @@ -0,0 +1,4 @@ +// bindgen-flags: --dynamic-loading TestLib + +int foo; +int *baz; \ No newline at end of file diff --git a/bindgen-tests/tests/headers/dynamic_loading_variable_with_allowlist.hpp b/bindgen-tests/tests/headers/dynamic_loading_variable_with_allowlist.hpp new file mode 100644 index 0000000000..5e27303063 --- /dev/null +++ b/bindgen-tests/tests/headers/dynamic_loading_variable_with_allowlist.hpp @@ -0,0 +1,5 @@ +// bindgen-flags: --dynamic-loading TestLib --allowlist-var foo --allowlist-var bar + +int foo; +int bar; +int baz; // should not be allowed \ No newline at end of file diff --git a/bindgen/codegen/dyngen.rs b/bindgen/codegen/dyngen.rs index b26c0b1817..4b2749ec0c 100644 --- a/bindgen/codegen/dyngen.rs +++ b/bindgen/codegen/dyngen.rs @@ -1,7 +1,7 @@ use crate::codegen; use crate::ir::context::BindgenContext; use crate::ir::function::ClangAbi; -use proc_macro2::Ident; +use proc_macro2::{Ident, TokenStream}; /// Used to build the output tokens for dynamic bindings. #[derive(Default)] @@ -122,7 +122,7 @@ impl DynamicItems { } #[allow(clippy::too_many_arguments)] - pub(crate) fn push( + pub(crate) fn push_func( &mut self, ident: Ident, abi: ClangAbi, @@ -196,4 +196,47 @@ impl DynamicItems { #ident }); } + + pub fn push_var( + &mut self, + ident: Ident, + ty: TokenStream, + is_required: bool, + ) { + let member = if is_required { + quote! { *mut #ty } + } else { + quote! { Result<*mut #ty, ::libloading::Error> } + }; + + self.struct_members.push(quote! { + pub #ident: #member, + }); + + let deref = if is_required { + quote! { self.#ident } + } else { + quote! { *self.#ident.as_ref().expect("Expected variable, got error.") } + }; + self.struct_implementation.push(quote! { + pub unsafe fn #ident (&self) -> *mut #ty { + #deref + } + }); + + let ident_str = codegen::helpers::ast_ty::cstr_expr(ident.to_string()); + self.constructor_inits.push(if is_required { + quote! { + let #ident = __library.get::<*mut #ty>(#ident_str).map(|sym| *sym)?; + } + } else { + quote! { + let #ident = __library.get::<*mut #ty>(#ident_str).map(|sym| *sym); + } + }); + + self.init_fields.push(quote! { + #ident + }); + } } diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 070d9dec6f..0770275d2e 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -53,7 +53,7 @@ use crate::ir::ty::{Type, TypeKind}; use crate::ir::var::Var; use proc_macro2::{Ident, Span}; -use quote::TokenStreamExt; +use quote::{ToTokens, TokenStreamExt}; use crate::{Entry, HashMap, HashSet}; use std::borrow::Cow; @@ -799,7 +799,17 @@ impl CodeGenerator for Var { } ); - result.push(tokens); + if ctx.options().dynamic_library_name.is_some() { + result.dynamic_items().push_var( + canonical_ident, + self.ty() + .to_rust_ty_or_opaque(ctx, &()) + .into_token_stream(), + ctx.options().dynamic_link_require_all, + ); + } else { + result.push(tokens); + } } } } @@ -4576,7 +4586,7 @@ impl CodeGenerator for Function { let args_identifiers = utils::fnsig_argument_identifiers(ctx, signature); let ret_ty = utils::fnsig_return_ty(ctx, signature); - result.dynamic_items().push( + result.dynamic_items().push_func( ident, abi, signature.is_variadic(),