use std::ffi::OsStr; use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; use libloading::Library; pub(crate) fn add_runtime_search_path(path: &Path) -> Result<()> { #[cfg(not(target_os = "windows"))] { let _ = path; Ok(()) } #[cfg(target_os = "windows")] { use std::os::windows::ffi::OsStrExt; use windows_sys::Win32::System::LibraryLoader::{ AddDllDirectory, LOAD_LIBRARY_SEARCH_SYSTEM32, LOAD_LIBRARY_SEARCH_USER_DIRS, SetDefaultDllDirectories, }; let canonical = canonicalize_path(path)?; let wide = canonical .as_os_str() .encode_wide() .chain(std::iter::once(0)) .collect::>(); unsafe { if SetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32, ) == 0 { anyhow::bail!( "failed to set default DLL directories: {}", std::io::Error::last_os_error() ); } if AddDllDirectory(wide.as_ptr()).is_null() { anyhow::bail!( "failed to add DLL directory: {}", std::io::Error::last_os_error() ); } } Ok(()) } } pub(crate) fn preload_library(path: &Path) -> Result<()> { let library = load_library_by_path(path)?; std::mem::forget(library); Ok(()) } pub fn load_library_by_name(name: &str) -> Result { open_library(OsStr::new(name)).with_context(|| format!("failed to load `{name}`")) } pub fn load_library_by_path(path: &Path) -> Result { let canonical = canonicalize_path(path)?; open_library(canonical.as_os_str()) .with_context(|| format!("failed to load `{}`", canonical.display())) } fn canonicalize_path(path: &Path) -> Result { path.canonicalize() .with_context(|| format!("failed to canonicalize `{}`", path.display())) } fn open_library(target: &OsStr) -> Result { #[cfg(target_os = "windows")] { Ok(unsafe { Library::new(target) }?) } #[cfg(not(target_os = "windows"))] { use libloading::os::unix::{Library as UnixLibrary, RTLD_GLOBAL, RTLD_NOW}; let library = unsafe { UnixLibrary::open(Some(target), RTLD_NOW | RTLD_GLOBAL) }?; Ok(library.into()) } }