rstsr_lapack_ffi/blas/
mod.rs1#![allow(non_snake_case)]
2#![allow(non_camel_case_types)]
3#![allow(clippy::missing_safety_doc)]
4#![allow(clippy::type_complexity)]
5#![allow(clippy::too_many_arguments)]
6
7pub const MOD_NAME: &str = module_path!();
8pub const LIB_NAME: &str = "BLAS"; pub const LIB_NAME_SHOW: &str = "BLAS"; pub const LIB_NAME_LINK: &str = "blas"; #[cfg(feature = "dynamic_loading")]
13mod dynamic_loading_specific {
14 use super::*;
15 use libloading::Library;
16 use std::fmt::Debug;
17 use std::sync::OnceLock;
18
19 fn get_lib_candidates() -> Vec<String> {
20 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
21 let mut candidates = vec![];
22
23 for paths in [format!("RSTSR_DYLOAD_{LIB_NAME}").as_str(), "RSTSR_DYLOAD"] {
25 if let Ok(path) = std::env::var(paths) {
26 candidates.extend(path.split(":").map(|s| s.to_string()).collect::<Vec<_>>());
27 }
28 }
29
30 let int_type = if cfg!(feature = "ilp64") { "64" } else { "32" };
32 let int_name = if cfg!(feature = "ilp64") { "ilp64" } else { "lp64" };
33
34 candidates.extend(vec![
35 format!("{DLL_PREFIX}blas{int_type}{DLL_SUFFIX}"),
36 format!("{DLL_PREFIX}blas_{int_type}{DLL_SUFFIX}"),
37 format!("{DLL_PREFIX}blas-{int_type}{DLL_SUFFIX}"),
38 format!("{DLL_PREFIX}blas_{int_name}{DLL_SUFFIX}"),
39 format!("{DLL_PREFIX}blas-{int_name}{DLL_SUFFIX}"),
40 format!("{DLL_PREFIX}blas{DLL_SUFFIX}"),
41 format!("{DLL_PREFIX}lapack{int_type}{DLL_SUFFIX}"),
42 format!("{DLL_PREFIX}lapack_{int_type}{DLL_SUFFIX}"),
43 format!("{DLL_PREFIX}lapack-{int_type}{DLL_SUFFIX}"),
44 format!("{DLL_PREFIX}lapack_{int_name}{DLL_SUFFIX}"),
45 format!("{DLL_PREFIX}lapack-{int_name}{DLL_SUFFIX}"),
46 format!("{DLL_PREFIX}lapack{DLL_SUFFIX}"),
47 format!("{DLL_PREFIX}lapacke{int_type}{DLL_SUFFIX}"),
48 format!("{DLL_PREFIX}lapacke_{int_type}{DLL_SUFFIX}"),
49 format!("{DLL_PREFIX}lapacke-{int_type}{DLL_SUFFIX}"),
50 format!("{DLL_PREFIX}lapacke_{int_name}{DLL_SUFFIX}"),
51 format!("{DLL_PREFIX}lapacke-{int_name}{DLL_SUFFIX}"),
52 format!("{DLL_PREFIX}lapacke{DLL_SUFFIX}"),
53 ]);
54 candidates
55 }
56
57 fn check_lib_loaded(lib: &DyLoadLib) -> bool {
58 lib.dgemm_.is_some()
59 }
60
61 fn panic_no_lib_found<S: Debug>(candidates: &[S], err_msg: &str) -> ! {
62 panic!(
63 r#"
64This happens in module `{MOD_NAME}`.
65Unable to dynamically load the {LIB_NAME_SHOW} (`{LIB_NAME_LINK}`) shared library.
66Candidates: {candidates:#?}
67
68Please check
69- if dynamic-loading is not desired, please disable the `dynamic_loading` feature in your `Cargo.toml` (by something like --no-default-features).
70- if you want to provide custom {LIB_NAME_SHOW} library, use environment variable `RSTSR_DYLOAD_{LIB_NAME}` or `RSTSR_DYLOAD` to specify the path to the library.
71- if `lib{LIB_NAME_LINK}.so` (linux) or `lib{LIB_NAME_LINK}.dylib` (macOS) or `lib{LIB_NAME_LINK}.dll` (Windows) is installed on your system.
72- if `LD_LIBRARY_PATH` (linux) or `DYLD_LIBRARY_PATH` (macOS) or `PATH` (Windows) environment variable is set correctly (any path that's visible to linker).
73- this crate does not use things like `LD_PRELOAD` or `DYLD_INSERT_LIBRARIES` to load the library.
74- this crate does not support static linking of libraries when dynamic-loading.
75
76Error message(s):
77{err_msg}
78"#
79 )
80 }
81
82 fn panic_condition_not_met<S: Debug>(candidates: &[S]) -> ! {
83 panic!(
84 r#"
85This happens in module `{MOD_NAME}`.
86Unable to dynamically load the {LIB_NAME_SHOW} (`{LIB_NAME_LINK}`) shared library, due to condition unfulfilled.
87Condition: `dgemm_` not found.
88Found libraries: {candidates:#?}
89
90Please check
91- if dynamic-loading is not desired, please disable the `dynamic_loading` feature in your `Cargo.toml` (by something like --no-default-features).
92- if you want to provide custom {LIB_NAME_SHOW} library, use environment variable `RSTSR_DYLOAD_{LIB_NAME}` or `RSTSR_DYLOAD` to specify the path to the library.
93- sequence of libraries matters: `RSTSR_DYLOAD_{LIB_NAME}` will be tried first, then `RSTSR_DYLOAD`, then system dynamic library search paths.
94"#
95 )
96 }
97
98 pub unsafe fn dyload_lib() -> &'static DyLoadLib {
99 static LIB: OnceLock<DyLoadLib> = OnceLock::new();
100
101 LIB.get_or_init(|| {
102 let candidates = get_lib_candidates();
103 let (mut libraries, mut libraries_path) = (vec![], vec![]);
104 let mut err_msg = String::new();
105 for candidate in &candidates {
106 match Library::new(candidate) {
107 Ok(l) => {
108 libraries.push(l);
109 libraries_path.push(candidate.to_string());
110 },
111 Err(e) => err_msg.push_str(&format!("Failed to load `{candidate}`: {e}\n")),
112 }
113 }
114 let lib = DyLoadLib::new(libraries, libraries_path);
115 if lib.__libraries.is_empty() {
116 panic_no_lib_found(&candidates, &err_msg);
117 }
118 if !check_lib_loaded(&lib) {
119 panic_condition_not_met(&lib.__libraries_path);
120 }
121 lib
122 })
123 }
124}
125
126#[cfg(feature = "dynamic_loading")]
127pub use dynamic_loading_specific::*;
128
129pub(crate) mod ffi_base;
132pub use ffi_base::*;
133
134#[cfg(not(feature = "dynamic_loading"))]
135pub(crate) mod ffi_extern;
136#[cfg(not(feature = "dynamic_loading"))]
137pub use ffi_extern::*;
138
139#[cfg(feature = "dynamic_loading")]
140pub(crate) mod dyload_compatible;
141#[cfg(feature = "dynamic_loading")]
142pub(crate) mod dyload_initializer;
143#[cfg(feature = "dynamic_loading")]
144pub(crate) mod dyload_struct;
145
146#[cfg(feature = "dynamic_loading")]
147pub use dyload_compatible::*;
148#[cfg(feature = "dynamic_loading")]
149pub use dyload_struct::*;
150
151#[test]
154fn playground() {
155 let time = std::time::Instant::now();
157 let l = unsafe { dyload_lib() };
158 println!("Time taken to load BLAS library: {:?}", time.elapsed());
159 println!("Loaded BLAS library: {:?}", l.__libraries);
160 println!("Loaded BLAS library: {:?}", l.dgemm_);
161
162 let a: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];
164 let b: Vec<f64> = vec![5.0, 6.0, 7.0, 8.0];
165 let mut c: f64 = 0.0;
166 let n = 4;
167 let incx = 1;
168 unsafe { ddotsub_(&n, a.as_ptr(), &incx, b.as_ptr(), &incx, &mut c) };
169 assert_eq!(c, 70.0);
170 let c = unsafe { ddot_(&n, a.as_ptr(), &incx, b.as_ptr(), &incx) };
171 assert_eq!(c, 70.0);
172}