use libloading::Library; use std::sync::LazyLock; static LIBRARY: LazyLock> = LazyLock::new(get_library); fn get_library() -> Option { let cuda_lib = std::env::var("ZLUDA_SPARSE_LIB") .ok() .unwrap_or_else(|| "/usr/local/cuda/lib64/libcusparse.so".to_string()); unsafe { Library::new(cuda_lib) }.ok() } macro_rules! unimplemented { ($($abi:literal fn $fn_name:ident( $($arg_id:ident : $arg_type:ty),* ) -> $ret_type:ty;)*) => { $( #[cfg_attr(not(test), no_mangle)] #[allow(improper_ctypes)] #[allow(improper_ctypes_definitions)] pub unsafe extern $abi fn $fn_name ( $( $arg_id : $arg_type),* ) -> $ret_type { use ::zluda_dump_common::ReprUsize; let internal_error_untyped: usize = <$ret_type as ReprUsize>::INTERNAL_ERROR; let internal_error: $ret_type = ReprUsize::from_usize(internal_error_untyped); let maybe_fn_ptr = (&*LIBRARY).as_ref().and_then(|lib| lib.get:: $ret_type>(concat!( stringify!($fn_name), "\0").as_bytes()).ok()); let fn_ptr = unwrap_or::unwrap_some_or!(maybe_fn_ptr, return internal_error); let export_table = unwrap_or::unwrap_some_or!(::zluda_dump_common::get_export_table(), return internal_error); let format_args = dark_api::FnFfiWrapper(|| { let mut writer = Vec::new(); let formatter = paste::paste! { ::format:: [< write_ $fn_name>] }; formatter(&mut writer $(, $arg_id)* ).ok(); dark_api::ByteVecFfi::new(writer) }); let underlying_fn = dark_api::FnFfiWrapper(|| { let result = fn_ptr( $( $arg_id),* ); ReprUsize::to_usize(result) }); ReprUsize::from_usize(export_table.logged_call( cglue::slice::CSliceRef::from_str(stringify!($fn_name)), cglue::trait_obj!(&format_args as dark_api::FnFfi), cglue::trait_obj!(&underlying_fn as dark_api::FnFfi), internal_error_untyped, <$ret_type as ReprUsize>::format_status) ) } )* }; } cuda_base::cusparse_function_declarations!(unimplemented);