Make resolve_name a stand-alone function.

This commit is contained in:
Simonas Kazlauskas
2020-08-23 20:14:20 +03:00
committed by Simonas Kazlauskas
parent 75527deec8
commit 7e5f290148
4 changed files with 57 additions and 145 deletions
+4 -2
View File
@@ -1,16 +1,18 @@
//! Project changelog
// TODO: for the next breaking release rename `Error::LoadLibraryW` to `Error::LoadLibraryExW`.
// TODO: for the next breaking release use `RTLD_LAZY | RTLD_LOCAL` by default on unix.
/// Release 0.6.3 (2020-08-22)
///
/// * Improve documentation, allowing to view all of the os-specific functionality from
/// documentation generated for any target;
/// * Add [`os::windows::Library::this`];
/// * Added constants to use with OS-specific `Library::open`.
/// * Added constants to use with OS-specific `Library::open`;
/// * Add [`library_filename`].
///
/// [`os::windows::Library::this`]: crate::os::windows::Library::this
/// [`library_filename`]: crate::library_filename
/// Release 0.6.2 (2020-05-06)
///
+32 -143
View File
@@ -45,12 +45,10 @@
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![cfg_attr(docsrs, feature(doc_cfg))]
use std::borrow::Cow;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::ffi::OsStr;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::ops::{self, Deref};
use std::ops;
use std::marker;
#[cfg(unix)]
@@ -89,13 +87,15 @@ impl Library {
/// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
///
/// Calling this function from multiple threads is not safe if used in conjunction with
/// path-less filename and library search path is modified (`SetDllDirectory` function on
/// relative filenames and the library search path is modified (`SetDllDirectory` function on
/// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
///
/// # Platform-specific behaviour
///
/// When a plain library filename is supplied, locations where library is searched for is
/// platform specific and cannot be adjusted in a portable manner.
/// platform specific and cannot be adjusted in a portable manner. See documentation for
/// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
/// for further information on library lookup behaviour.
///
/// ## Windows
///
@@ -113,9 +113,10 @@ impl Library {
/// `awesome.module`) allows to avoid code which has to account for platforms conventional
/// library filenames.
///
/// Strive to specify absolute or relative path to your library, unless system-wide libraries
/// are being loaded. Platform-dependent library search locations combined with various quirks
/// related to path-less filenames may cause flaky code.
/// Strive to specify an absolute or at least a relative path to your library, unless
/// system-wide libraries are being loaded. Platform-dependent library search locations
/// combined with various quirks related to path-less filenames may cause flakiness in
/// programs.
///
/// # Examples
///
@@ -130,35 +131,6 @@ impl Library {
imp::Library::new(filename).map(From::from)
}
fn resolve_name<'a>(name: &'a str) -> Cow<'a, str> {
match (name.starts_with(DLL_PREFIX), name.ends_with(DLL_SUFFIX)) {
(true, true) => Cow::Borrowed(name),
(true, false) => Cow::Owned(format!("{}{}", name, DLL_SUFFIX)),
(false, true) => Cow::Owned(format!("{}{}", DLL_PREFIX, name)),
(false, false) => Cow::Owned(format!("{}{}{}", DLL_PREFIX, name, DLL_SUFFIX)),
}
}
/// Loads a library and does resolve it's name to match platform-specific
/// naming schemes.
///
/// For a given library called `engine`, this method will resolve the name
/// to the following:
/// - `Linux`: `libengine.so`
/// - `macOS`: `libengine.dylib`
/// - `Windows`: `engine.dll`
///
/// # Note
///
/// This function does only work with library names and does not work when
/// supplying a path to a library. The function assumes that the library is
/// already present inside a path that is detectable and searchable by the
/// OS during runtime.
pub fn with_name_resolve<T: AsRef<str>>(libname: T) -> Result<Library, Error> {
let resolved_name = Self::resolve_name(libname.as_ref());
Self::new(resolved_name.deref())
}
/// Get a pointer to function or static variable by symbol name.
///
/// The `symbol` may not contain any null bytes, with an exception of last byte. A null
@@ -369,109 +341,26 @@ impl<'lib, T> fmt::Debug for Symbol<'lib, T> {
unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
#[cfg(test)]
mod tests {
use super::Library;
#[cfg(target_os = "windows")]
#[test]
fn test_resolve_name_none() {
let name = "audioengine";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "audioengine.dll");
}
#[cfg(target_os = "linux")]
#[test]
fn test_resolve_name_none() {
let name = "audioengine";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.so");
}
#[cfg(target_os = "macos")]
#[test]
fn test_resolve_name_none() {
let name = "audioengine";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.dylib");
}
// prefix only
#[cfg(target_os = "windows")]
#[test]
fn test_resolve_name_prefix() {
let name = "audioengine";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "audioengine.dll");
}
#[cfg(target_os = "linux")]
#[test]
fn test_resolve_name_prefix() {
let name = "libaudioengine";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.so");
}
#[cfg(target_os = "macos")]
#[test]
fn test_resolve_name_prefix() {
let name = "libaudioengine";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.dylib");
}
// suffix only
#[cfg(target_os = "windows")]
#[test]
fn test_resolve_name_suffix() {
let name = "audioengine.dll";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "audioengine.dll");
}
#[cfg(target_os = "linux")]
#[test]
fn test_resolve_name_suffix() {
let name = "audioengine.so";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.so");
}
#[cfg(target_os = "macos")]
#[test]
fn test_resolve_name_suffix() {
let name = "audioengine.dylib";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.dylib");
}
// both
#[cfg(target_os = "windows")]
#[test]
fn test_resolve_name_prefix_and_suffix() {
let name = "audioengine.dll";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "audioengine.dll");
}
#[cfg(target_os = "linux")]
#[test]
fn test_resolve_name_prefix_and_suffix() {
let name = "libaudioengine.so";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.so");
}
#[cfg(target_os = "macos")]
#[test]
fn test_resolve_name_prefix_and_suffix() {
let name = "libaudioengine.dylib";
let resolved = Library::resolve_name(name);
assert_eq!(&resolved, "libaudioengine.dylib");
}
/// Converts a library name to a filename generally appropriate for use on the system.
///
/// The function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library
/// `name` to construct the filename.
///
/// # Examples
///
/// It can be used to load global libraries in a platform independent manner:
///
/// ```
/// use libloading::{Library, library_filename};
/// // Will attempt to load `libLLVM.so` on Linux, `libLLVM.dylib` on macOS and `LLVM.dll` on
/// // Windows.
/// let library = Library::new(library_filename("LLVM"));
/// ```
pub fn library_filename<S: AsRef<OsStr>>(name: S) -> OsString {
let name = name.as_ref();
let mut string = OsString::with_capacity(name.len() + DLL_PREFIX.len() + DLL_SUFFIX.len());
string.push(DLL_PREFIX);
string.push(name);
string.push(DLL_SUFFIX);
string
}
+4
View File
@@ -84,6 +84,10 @@ impl Library {
/// path, the function uses a windows-specific search strategy to find the module; for more
/// information, see the [Remarks on MSDN][msdn].
///
/// If the `filename` specifies a library filename without path and with extension omitted,
/// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
/// trailing `.` to the `filename`.
///
/// This is equivalent to [`Library::load_with_flags`]`(filename, 0)`.
///
/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw#remarks
+17
View File
@@ -0,0 +1,17 @@
extern crate libloading;
use libloading::library_filename;
use std::path::Path;
#[cfg(target_os = "windows")]
const EXPECTED: &str = "audioengine.dll";
#[cfg(target_os = "linux")]
const EXPECTED: &str = "libaudioengine.so";
#[cfg(target_os = "macos")]
const EXPECTED: &str = "libaudioengine.dylib";
#[test]
fn test_library_filename() {
let name = "audioengine";
let resolved = library_filename(name);
assert!(Path::new(&resolved).ends_with(EXPECTED));
}