#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::type_complexity)]
#![allow(clippy::too_many_arguments)]
pub const MOD_NAME: &str = module_path!();
pub const LIB_NAME: &str = "CUEST";
pub const LIB_NAME_SHOW: &str = "cuEST";
pub const LIB_NAME_LINK: &str = "cuest";
mod dynamic_loading_specific {
use super::*;
use libloading::Library;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::fmt::Debug;
use std::sync::OnceLock;
fn lib_names() -> Vec<String> {
vec![
format!("{DLL_PREFIX}{LIB_NAME_LINK}{DLL_SUFFIX}"),
format!("{DLL_PREFIX}{LIB_NAME_LINK}{DLL_SUFFIX}.0"),
]
}
static PYTHON_LIB_PATH: OnceLock<Vec<String>> = OnceLock::new();
fn extract_base_from_python_bin(python_bin: &str) -> Option<String> {
let bin_path = std::path::Path::new(python_bin);
bin_path.parent()?.parent().map(|base| base.to_string_lossy().to_string())
}
fn push_python_base(base: &str, lib_paths: &mut Vec<String>) {
let lib_path = std::path::Path::new(base).join("lib");
if !lib_path.exists() {
return;
}
lib_paths.push(lib_path.to_string_lossy().to_string());
if let Ok(entries) = std::fs::read_dir(&lib_path) {
for entry in entries.flatten() {
if !entry.file_name().to_string_lossy().starts_with("python") {
continue;
}
for site in ["site-packages", "dist-packages"] {
let wheel_lib = entry.path().join(site).join("nvidia/cuest/lib");
if wheel_lib.exists() {
lib_paths.push(wheel_lib.to_string_lossy().to_string());
}
}
}
}
}
fn detect_python_lib_paths() -> Vec<String> {
PYTHON_LIB_PATH
.get_or_init(|| {
let mut lib_paths = vec![];
if let Ok(python_path) = std::env::var("CUEST_PYTHON_PATH") {
if let Some(base) = extract_base_from_python_bin(&python_path) {
push_python_base(&base, &mut lib_paths);
}
}
if let Ok(conda_prefix) = std::env::var("CONDA_PREFIX") {
push_python_base(&conda_prefix, &mut lib_paths);
}
if let Ok(paths) = std::env::var("PATH") {
for name in ["python", "python3"] {
for path in paths.split(":") {
let python_bin = format!("{path}/{name}");
if std::path::Path::new(&python_bin).exists() {
if let Some(base) = extract_base_from_python_bin(&python_bin) {
push_python_base(&base, &mut lib_paths);
}
}
}
}
}
lib_paths.dedup();
lib_paths
})
.clone()
}
fn get_lib_candidates() -> Vec<String> {
let names = lib_names();
let mut candidates = vec![];
for env_var in [format!("CUEST_DYLOAD_{LIB_NAME}").as_str(), "CUEST_DYLOAD"] {
if let Ok(path) = std::env::var(env_var) {
for path in path.split(":").filter(|p| !p.is_empty()) {
if std::path::Path::new(path).is_dir() {
for name in &names {
candidates.push(format!("{path}/{name}"));
}
} else {
candidates.push(path.to_string());
}
}
}
}
let mut dirs = vec![];
for env_var in [
"LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "DYLD_FALLBACK_LIBRARY_PATH", "PATH", ] {
if let Ok(paths) = std::env::var(env_var) {
dirs.extend(paths.split(":").map(|path| path.to_string()));
}
}
dirs.extend(detect_python_lib_paths());
dirs.extend(["/usr/lib".to_string(), "/usr/local/lib".to_string(), "/lib".to_string()]);
for dir in dirs {
for name in &names {
candidates.push(format!("{dir}/{name}"));
}
}
candidates.extend(names);
candidates
}
fn check_lib_loaded(lib: &DyLoadLib) -> bool {
lib.cuestCreate.is_some()
}
fn panic_no_lib_found<S: Debug>(candidates: &[S], err_msg: &str) -> ! {
panic!(
r#"
This happens in module `{MOD_NAME}`.
Unable to dynamically load the {LIB_NAME_SHOW} (`{LIB_NAME_LINK}`) shared library.
Candidates: {candidates:#?}
Please check:
- If dynamic-loading is not desired, disable the `dynamic_loading` feature in Cargo.toml.
- Use environment variable `CUEST_DYLOAD_{LIB_NAME}` or `CUEST_DYLOAD` to specify the library path.
- If `lib{LIB_NAME_LINK}.so` is installed on your system.
- If `LD_LIBRARY_PATH` is set correctly.
- Python interpreter path discovery: if Python is at `/path/bin/python`, the
library is expected at `/path/lib/libcuest.so` or under the pip wheel layout
`/path/lib/python3.*/site-packages/nvidia/cuest/lib/libcuest.so`.
Error message(s):
{err_msg}
"#
)
}
fn panic_condition_not_met<S: Debug>(candidates: &[S]) -> ! {
panic!(
r#"
This happens in module `{MOD_NAME}`.
Library loaded but condition not met: `cuestCreate` not found.
Found libraries: {candidates:#?}
Please check that the loaded library is a valid cuEST library.
"#
)
}
pub unsafe fn dyload_lib() -> &'static DyLoadLib {
static LIB: OnceLock<DyLoadLib> = OnceLock::new();
LIB.get_or_init(|| {
let candidates = get_lib_candidates();
let (mut libraries, mut libraries_path) = (vec![], vec![]);
let mut err_msg = String::new();
for candidate in &candidates {
match Library::new(candidate) {
Ok(l) => {
libraries.push(l);
libraries_path.push(candidate.to_string());
},
Err(e) => err_msg.push_str(&format!("Failed to load `{candidate}`: {e}\n")),
}
}
let lib = DyLoadLib::new(libraries, libraries_path);
if lib.__libraries.is_empty() {
panic_no_lib_found(&candidates, &err_msg);
}
if !check_lib_loaded(&lib) {
panic_condition_not_met(&lib.__libraries_path);
}
lib
})
}
}
pub use dynamic_loading_specific::*;
pub(crate) mod ffi_base;
pub use ffi_base::*;
pub(crate) mod dyload_compatible;
pub(crate) mod dyload_initializer;
pub(crate) mod dyload_struct;
pub use dyload_compatible::*;
pub use dyload_struct::*;