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(),