Skip to content

Commit ae8d55b

Browse files
committed
Make resolve_name a stand-alone function.
1 parent 4ce2e44 commit ae8d55b

File tree

4 files changed

+57
-145
lines changed

4 files changed

+57
-145
lines changed

src/changelog.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
//! Project changelog
22
33
// TODO: for the next breaking release rename `Error::LoadLibraryW` to `Error::LoadLibraryExW`.
4-
4+
// TODO: for the next breaking release use `RTLD_LAZY | RTLD_LOCAL` by default on unix.
55

66
/// Release 0.6.3 (2020-08-22)
77
///
88
/// * Improve documentation, allowing to view all of the os-specific functionality from
99
/// documentation generated for any target;
1010
/// * Add [`os::windows::Library::this`];
11-
/// * Added constants to use with OS-specific `Library::open`.
11+
/// * Added constants to use with OS-specific `Library::open`;
12+
/// * Add [`library_filename`].
1213
///
1314
/// [`os::windows::Library::this`]: crate::os::windows::Library::this
15+
/// [`library_filename`]: crate::library_filename
1416
1517
/// Release 0.6.2 (2020-05-06)
1618
///

src/lib.rs

Lines changed: 32 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,10 @@
4545
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
4646
#![cfg_attr(docsrs, feature(doc_cfg))]
4747

48-
49-
use std::borrow::Cow;
5048
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
51-
use std::ffi::OsStr;
49+
use std::ffi::{OsStr, OsString};
5250
use std::fmt;
53-
use std::ops::{self, Deref};
51+
use std::ops;
5452
use std::marker;
5553

5654
#[cfg(unix)]
@@ -89,13 +87,15 @@ impl Library {
8987
/// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
9088
///
9189
/// Calling this function from multiple threads is not safe if used in conjunction with
92-
/// path-less filename and library search path is modified (`SetDllDirectory` function on
90+
/// relative filenames and the library search path is modified (`SetDllDirectory` function on
9391
/// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX).
9492
///
9593
/// # Platform-specific behaviour
9694
///
9795
/// When a plain library filename is supplied, locations where library is searched for is
98-
/// platform specific and cannot be adjusted in a portable manner.
96+
/// platform specific and cannot be adjusted in a portable manner. See documentation for
97+
/// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods
98+
/// for further information on library lookup behaviour.
9999
///
100100
/// ## Windows
101101
///
@@ -113,9 +113,10 @@ impl Library {
113113
/// `awesome.module`) allows to avoid code which has to account for platform’s conventional
114114
/// library filenames.
115115
///
116-
/// Strive to specify absolute or relative path to your library, unless system-wide libraries
117-
/// are being loaded. Platform-dependent library search locations combined with various quirks
118-
/// related to path-less filenames may cause flaky code.
116+
/// Strive to specify an absolute or at least a relative path to your library, unless
117+
/// system-wide libraries are being loaded. Platform-dependent library search locations
118+
/// combined with various quirks related to path-less filenames may cause flakiness in
119+
/// programs.
119120
///
120121
/// # Examples
121122
///
@@ -130,35 +131,6 @@ impl Library {
130131
imp::Library::new(filename).map(From::from)
131132
}
132133

133-
fn resolve_name<'a>(name: &'a str) -> Cow<'a, str> {
134-
match (name.starts_with(DLL_PREFIX), name.ends_with(DLL_SUFFIX)) {
135-
(true, true) => Cow::Borrowed(name),
136-
(true, false) => Cow::Owned(format!("{}{}", name, DLL_SUFFIX)),
137-
(false, true) => Cow::Owned(format!("{}{}", DLL_PREFIX, name)),
138-
(false, false) => Cow::Owned(format!("{}{}{}", DLL_PREFIX, name, DLL_SUFFIX)),
139-
}
140-
}
141-
142-
/// Loads a library and does resolve it's name to match platform-specific
143-
/// naming schemes.
144-
///
145-
/// For a given library called `engine`, this method will resolve the name
146-
/// to the following:
147-
/// - `Linux`: `libengine.so`
148-
/// - `macOS`: `libengine.dylib`
149-
/// - `Windows`: `engine.dll`
150-
///
151-
/// # Note
152-
///
153-
/// This function does only work with library names and does not work when
154-
/// supplying a path to a library. The function assumes that the library is
155-
/// already present inside a path that is detectable and searchable by the
156-
/// OS during runtime.
157-
pub fn with_name_resolve<T: AsRef<str>>(libname: T) -> Result<Library, Error> {
158-
let resolved_name = Self::resolve_name(libname.as_ref());
159-
Self::new(resolved_name.deref())
160-
}
161-
162134
/// Get a pointer to function or static variable by symbol name.
163135
///
164136
/// 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> {
369341
unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {}
370342
unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {}
371343

372-
#[cfg(test)]
373-
mod tests {
374-
use super::Library;
375-
376-
#[cfg(target_os = "windows")]
377-
#[test]
378-
fn test_resolve_name_none() {
379-
let name = "audioengine";
380-
let resolved = Library::resolve_name(name);
381-
assert_eq!(&resolved, "audioengine.dll");
382-
}
383-
384-
#[cfg(target_os = "linux")]
385-
#[test]
386-
fn test_resolve_name_none() {
387-
let name = "audioengine";
388-
let resolved = Library::resolve_name(name);
389-
assert_eq!(&resolved, "libaudioengine.so");
390-
}
391-
392-
#[cfg(target_os = "macos")]
393-
#[test]
394-
fn test_resolve_name_none() {
395-
let name = "audioengine";
396-
let resolved = Library::resolve_name(name);
397-
assert_eq!(&resolved, "libaudioengine.dylib");
398-
}
399-
400-
// prefix only
401-
402-
#[cfg(target_os = "windows")]
403-
#[test]
404-
fn test_resolve_name_prefix() {
405-
let name = "audioengine";
406-
let resolved = Library::resolve_name(name);
407-
assert_eq!(&resolved, "audioengine.dll");
408-
}
409-
410-
#[cfg(target_os = "linux")]
411-
#[test]
412-
fn test_resolve_name_prefix() {
413-
let name = "libaudioengine";
414-
let resolved = Library::resolve_name(name);
415-
assert_eq!(&resolved, "libaudioengine.so");
416-
}
417-
418-
#[cfg(target_os = "macos")]
419-
#[test]
420-
fn test_resolve_name_prefix() {
421-
let name = "libaudioengine";
422-
let resolved = Library::resolve_name(name);
423-
assert_eq!(&resolved, "libaudioengine.dylib");
424-
}
425-
426-
// suffix only
427-
428-
#[cfg(target_os = "windows")]
429-
#[test]
430-
fn test_resolve_name_suffix() {
431-
let name = "audioengine.dll";
432-
let resolved = Library::resolve_name(name);
433-
assert_eq!(&resolved, "audioengine.dll");
434-
}
435-
436-
#[cfg(target_os = "linux")]
437-
#[test]
438-
fn test_resolve_name_suffix() {
439-
let name = "audioengine.so";
440-
let resolved = Library::resolve_name(name);
441-
assert_eq!(&resolved, "libaudioengine.so");
442-
}
443-
444-
#[cfg(target_os = "macos")]
445-
#[test]
446-
fn test_resolve_name_suffix() {
447-
let name = "audioengine.dylib";
448-
let resolved = Library::resolve_name(name);
449-
assert_eq!(&resolved, "libaudioengine.dylib");
450-
}
451-
452-
// both
453-
454-
#[cfg(target_os = "windows")]
455-
#[test]
456-
fn test_resolve_name_prefix_and_suffix() {
457-
let name = "audioengine.dll";
458-
let resolved = Library::resolve_name(name);
459-
assert_eq!(&resolved, "audioengine.dll");
460-
}
461-
462-
#[cfg(target_os = "linux")]
463-
#[test]
464-
fn test_resolve_name_prefix_and_suffix() {
465-
let name = "libaudioengine.so";
466-
let resolved = Library::resolve_name(name);
467-
assert_eq!(&resolved, "libaudioengine.so");
468-
}
469-
470-
#[cfg(target_os = "macos")]
471-
#[test]
472-
fn test_resolve_name_prefix_and_suffix() {
473-
let name = "libaudioengine.dylib";
474-
let resolved = Library::resolve_name(name);
475-
assert_eq!(&resolved, "libaudioengine.dylib");
476-
}
344+
/// Converts a library name to a filename generally appropriate for use on the system.
345+
///
346+
/// The function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library
347+
/// `name` to construct the filename.
348+
///
349+
/// # Examples
350+
///
351+
/// It can be used to load global libraries in a platform independent manner:
352+
///
353+
/// ```
354+
/// use libloading::{Library, library_filename};
355+
/// // Will attempt to load `libLLVM.so` on Linux, `libLLVM.dylib` on macOS and `LLVM.dll` on
356+
/// // Windows.
357+
/// let library = Library::new(library_filename("LLVM"));
358+
/// ```
359+
pub fn library_filename<S: AsRef<OsStr>>(name: S) -> OsString {
360+
let name = name.as_ref();
361+
let mut string = OsString::with_capacity(name.len() + DLL_PREFIX.len() + DLL_SUFFIX.len());
362+
string.push(DLL_PREFIX);
363+
string.push(name);
364+
string.push(DLL_SUFFIX);
365+
string
477366
}

src/os/windows/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ impl Library {
8484
/// path, the function uses a windows-specific search strategy to find the module; for more
8585
/// information, see the [Remarks on MSDN][msdn].
8686
///
87+
/// If the `filename` specifies a library filename without path and with extension omitted,
88+
/// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a
89+
/// trailing `.` to the `filename`.
90+
///
8791
/// This is equivalent to [`Library::load_with_flags`]`(filename, 0)`.
8892
///
8993
/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw#remarks

tests/library_filename.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
extern crate libloading;
2+
use libloading::library_filename;
3+
use std::path::Path;
4+
5+
#[cfg(target_os = "windows")]
6+
const EXPECTED: &str = "audioengine.dll";
7+
#[cfg(target_os = "linux")]
8+
const EXPECTED: &str = "libaudioengine.so";
9+
#[cfg(target_os = "macos")]
10+
const EXPECTED: &str = "libaudioengine.dylib";
11+
12+
#[test]
13+
fn test_library_filename() {
14+
let name = "audioengine";
15+
let resolved = library_filename(name);
16+
assert!(Path::new(&resolved).ends_with(EXPECTED));
17+
}

0 commit comments

Comments
 (0)