]>
Commit | Line | Data |
---|---|---|
a2a8927a | 1 | use super::Error; |
5099ac24 | 2 | #[cfg(libloading_docs)] |
a2a8927a | 3 | use super::os::unix as imp; // the implementation used here doesn't matter particularly much... |
5099ac24 | 4 | #[cfg(all(not(libloading_docs), unix))] |
a2a8927a | 5 | use super::os::unix as imp; |
5099ac24 | 6 | #[cfg(all(not(libloading_docs), windows))] |
a2a8927a XL |
7 | use super::os::windows as imp; |
8 | use std::ffi::OsStr; | |
9 | use std::fmt; | |
10 | use std::marker; | |
11 | use std::ops; | |
12 | ||
13 | /// A loaded dynamic library. | |
5099ac24 | 14 | #[cfg_attr(libloading_docs, doc(cfg(any(unix, windows))))] |
a2a8927a XL |
15 | pub struct Library(imp::Library); |
16 | ||
17 | impl Library { | |
18 | /// Find and load a dynamic library. | |
19 | /// | |
20 | /// The `filename` argument may be either: | |
21 | /// | |
22 | /// * A library filename; | |
23 | /// * The absolute path to the library; | |
24 | /// * A relative (to the current working directory) path to the library. | |
25 | /// | |
26 | /// # Safety | |
27 | /// | |
28 | /// When a library is loaded, initialisation routines contained within it are executed. | |
29 | /// For the purposes of safety, the execution of these routines is conceptually the same calling an | |
30 | /// unknown foreign function and may impose arbitrary requirements on the caller for the call | |
31 | /// to be sound. | |
32 | /// | |
33 | /// Additionally, the callers of this function must also ensure that execution of the | |
34 | /// termination routines contained within the library is safe as well. These routines may be | |
35 | /// executed when the library is unloaded. | |
36 | /// | |
37 | /// # Thread-safety | |
38 | /// | |
39 | /// The implementation strives to be as MT-safe as sanely possible, however on certain | |
40 | /// platforms the underlying error-handling related APIs not always MT-safe. This library | |
41 | /// shares these limitations on those platforms. In particular, on certain UNIX targets | |
42 | /// `dlerror` is not MT-safe, resulting in garbage error messages in certain MT-scenarios. | |
43 | /// | |
44 | /// Calling this function from multiple threads is not MT-safe if used in conjunction with | |
45 | /// library filenames and the library search path is modified (`SetDllDirectory` function on | |
46 | /// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX). | |
47 | /// | |
48 | /// # Platform-specific behaviour | |
49 | /// | |
50 | /// When a plain library filename is supplied, the locations in which the library is searched are | |
51 | /// platform specific and cannot be adjusted in a portable manner. See the documentation for | |
52 | /// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods | |
53 | /// for further information on library lookup behaviour. | |
54 | /// | |
55 | /// If the `filename` specifies a library filename without a path and with the extension omitted, | |
56 | /// the `.dll` extension is implicitly added on Windows. | |
57 | /// | |
58 | /// [`os::unix::Library::new`]: crate::os::unix::Library::new | |
59 | /// [`os::windows::Library::new`]: crate::os::windows::Library::new | |
60 | /// | |
61 | /// # Tips | |
62 | /// | |
63 | /// Distributing your dynamic libraries under a filename common to all platforms (e.g. | |
64 | /// `awesome.module`) allows you to avoid code which has to account for platform’s conventional | |
65 | /// library filenames. | |
66 | /// | |
67 | /// Strive to specify an absolute or at least a relative path to your library, unless | |
68 | /// system-wide libraries are being loaded. Platform-dependent library search locations | |
69 | /// combined with various quirks related to path-less filenames may cause flakiness in | |
70 | /// programs. | |
71 | /// | |
72 | /// # Examples | |
73 | /// | |
74 | /// ```no_run | |
75 | /// # use ::libloading::Library; | |
76 | /// // Any of the following are valid. | |
77 | /// unsafe { | |
78 | /// let _ = Library::new("/path/to/awesome.module").unwrap(); | |
79 | /// let _ = Library::new("../awesome.module").unwrap(); | |
80 | /// let _ = Library::new("libsomelib.so.1").unwrap(); | |
81 | /// } | |
82 | /// ``` | |
83 | pub unsafe fn new<P: AsRef<OsStr>>(filename: P) -> Result<Library, Error> { | |
84 | imp::Library::new(filename).map(From::from) | |
85 | } | |
86 | ||
87 | /// Get a pointer to a function or static variable by symbol name. | |
88 | /// | |
89 | /// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a | |
90 | /// null-terminated `symbol` may help to avoid an allocation. | |
91 | /// | |
92 | /// The symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are | |
93 | /// most likely invalid. | |
94 | /// | |
95 | /// # Safety | |
96 | /// | |
97 | /// Users of this API must specify the correct type of the function or variable loaded. | |
98 | /// | |
99 | /// # Platform-specific behaviour | |
100 | /// | |
101 | /// The implementation of thread-local variables is extremely platform specific and uses of such | |
102 | /// variables that work on e.g. Linux may have unintended behaviour on other targets. | |
103 | /// | |
104 | /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such | |
105 | /// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym` | |
106 | /// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null | |
107 | /// pointer without it being an error. If loading a null pointer is something you care about, | |
108 | /// consider using the [`os::unix::Library::get_singlethreaded`] call. | |
109 | /// | |
110 | /// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded | |
111 | /// | |
112 | /// # Examples | |
113 | /// | |
114 | /// Given a loaded library: | |
115 | /// | |
116 | /// ```no_run | |
117 | /// # use ::libloading::Library; | |
118 | /// let lib = unsafe { | |
119 | /// Library::new("/path/to/awesome.module").unwrap() | |
120 | /// }; | |
121 | /// ``` | |
122 | /// | |
123 | /// Loading and using a function looks like this: | |
124 | /// | |
125 | /// ```no_run | |
126 | /// # use ::libloading::{Library, Symbol}; | |
127 | /// # let lib = unsafe { | |
128 | /// # Library::new("/path/to/awesome.module").unwrap() | |
129 | /// # }; | |
130 | /// unsafe { | |
131 | /// let awesome_function: Symbol<unsafe extern fn(f64) -> f64> = | |
132 | /// lib.get(b"awesome_function\0").unwrap(); | |
133 | /// awesome_function(0.42); | |
134 | /// } | |
135 | /// ``` | |
136 | /// | |
137 | /// A static variable may also be loaded and inspected: | |
138 | /// | |
139 | /// ```no_run | |
140 | /// # use ::libloading::{Library, Symbol}; | |
141 | /// # let lib = unsafe { Library::new("/path/to/awesome.module").unwrap() }; | |
142 | /// unsafe { | |
143 | /// let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap(); | |
144 | /// **awesome_variable = 42.0; | |
145 | /// }; | |
146 | /// ``` | |
147 | pub unsafe fn get<'lib, T>(&'lib self, symbol: &[u8]) -> Result<Symbol<'lib, T>, Error> { | |
148 | self.0.get(symbol).map(|from| Symbol::from_raw(from, self)) | |
149 | } | |
150 | ||
151 | /// Unload the library. | |
152 | /// | |
153 | /// This method might be a no-op, depending on the flags with which the `Library` was opened, | |
154 | /// what library was opened or other platform specifics. | |
155 | /// | |
156 | /// You only need to call this if you are interested in handling any errors that may arise when | |
157 | /// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the | |
158 | /// library and ignore the errors were they arise. | |
159 | /// | |
160 | /// The underlying data structures may still get leaked if an error does occur. | |
161 | pub fn close(self) -> Result<(), Error> { | |
162 | self.0.close() | |
163 | } | |
164 | } | |
165 | ||
166 | impl fmt::Debug for Library { | |
167 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
168 | self.0.fmt(f) | |
169 | } | |
170 | } | |
171 | ||
172 | impl From<imp::Library> for Library { | |
173 | fn from(lib: imp::Library) -> Library { | |
174 | Library(lib) | |
175 | } | |
176 | } | |
177 | ||
178 | impl From<Library> for imp::Library { | |
179 | fn from(lib: Library) -> imp::Library { | |
180 | lib.0 | |
181 | } | |
182 | } | |
183 | ||
184 | unsafe impl Send for Library {} | |
185 | unsafe impl Sync for Library {} | |
186 | ||
187 | /// Symbol from a library. | |
188 | /// | |
189 | /// This type is a safeguard against using dynamically loaded symbols after a `Library` is | |
190 | /// unloaded. The primary method to create an instance of a `Symbol` is via [`Library::get`]. | |
191 | /// | |
192 | /// The `Deref` trait implementation allows the use of `Symbol` as if it was a function or variable | |
193 | /// itself, without taking care to “extract” the function or variable manually most of the time. | |
194 | /// | |
195 | /// [`Library::get`]: Library::get | |
5099ac24 | 196 | #[cfg_attr(libloading_docs, doc(cfg(any(unix, windows))))] |
a2a8927a XL |
197 | pub struct Symbol<'lib, T: 'lib> { |
198 | inner: imp::Symbol<T>, | |
199 | pd: marker::PhantomData<&'lib T>, | |
200 | } | |
201 | ||
202 | impl<'lib, T> Symbol<'lib, T> { | |
203 | /// Extract the wrapped `os::platform::Symbol`. | |
204 | /// | |
205 | /// # Safety | |
206 | /// | |
207 | /// Using this function relinquishes all the lifetime guarantees. It is up to the developer to | |
208 | /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol | |
209 | /// was loaded from. | |
210 | /// | |
211 | /// # Examples | |
212 | /// | |
213 | /// ```no_run | |
214 | /// # use ::libloading::{Library, Symbol}; | |
215 | /// unsafe { | |
216 | /// let lib = Library::new("/path/to/awesome.module").unwrap(); | |
217 | /// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap(); | |
218 | /// let symbol = symbol.into_raw(); | |
219 | /// } | |
220 | /// ``` | |
221 | pub unsafe fn into_raw(self) -> imp::Symbol<T> { | |
222 | self.inner | |
223 | } | |
224 | ||
225 | /// Wrap the `os::platform::Symbol` into this safe wrapper. | |
226 | /// | |
227 | /// Note that, in order to create association between the symbol and the library this symbol | |
228 | /// came from, this function requires a reference to the library. | |
229 | /// | |
230 | /// # Safety | |
231 | /// | |
232 | /// The `library` reference must be exactly the library `sym` was loaded from. | |
233 | /// | |
234 | /// # Examples | |
235 | /// | |
236 | /// ```no_run | |
237 | /// # use ::libloading::{Library, Symbol}; | |
238 | /// unsafe { | |
239 | /// let lib = Library::new("/path/to/awesome.module").unwrap(); | |
240 | /// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap(); | |
241 | /// let symbol = symbol.into_raw(); | |
242 | /// let symbol = Symbol::from_raw(symbol, &lib); | |
243 | /// } | |
244 | /// ``` | |
245 | pub unsafe fn from_raw<L>(sym: imp::Symbol<T>, library: &'lib L) -> Symbol<'lib, T> { | |
246 | let _ = library; // ignore here for documentation purposes. | |
247 | Symbol { | |
248 | inner: sym, | |
249 | pd: marker::PhantomData, | |
250 | } | |
251 | } | |
252 | } | |
253 | ||
254 | impl<'lib, T> Symbol<'lib, Option<T>> { | |
255 | /// Lift Option out of the symbol. | |
256 | /// | |
257 | /// # Examples | |
258 | /// | |
259 | /// ```no_run | |
260 | /// # use ::libloading::{Library, Symbol}; | |
261 | /// unsafe { | |
262 | /// let lib = Library::new("/path/to/awesome.module").unwrap(); | |
263 | /// let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap(); | |
264 | /// let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null"); | |
265 | /// } | |
266 | /// ``` | |
267 | pub fn lift_option(self) -> Option<Symbol<'lib, T>> { | |
268 | self.inner.lift_option().map(|is| Symbol { | |
269 | inner: is, | |
270 | pd: marker::PhantomData, | |
271 | }) | |
272 | } | |
273 | } | |
274 | ||
275 | impl<'lib, T> Clone for Symbol<'lib, T> { | |
276 | fn clone(&self) -> Symbol<'lib, T> { | |
277 | Symbol { | |
278 | inner: self.inner.clone(), | |
279 | pd: marker::PhantomData, | |
280 | } | |
281 | } | |
282 | } | |
283 | ||
284 | // FIXME: implement FnOnce for callable stuff instead. | |
285 | impl<'lib, T> ops::Deref for Symbol<'lib, T> { | |
286 | type Target = T; | |
287 | fn deref(&self) -> &T { | |
288 | ops::Deref::deref(&self.inner) | |
289 | } | |
290 | } | |
291 | ||
292 | impl<'lib, T> fmt::Debug for Symbol<'lib, T> { | |
293 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
294 | self.inner.fmt(f) | |
295 | } | |
296 | } | |
297 | ||
298 | unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {} | |
299 | unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {} |