abi_stable/library.rs
1//! Traits and types related to loading an abi_stable dynamic library,
2//! as well as functions/modules within.
3//!
4//! # Loading the root module
5//!
6//! When you use the [`RootModule`]`::load_from*` associated functions,
7//! the root module of a library is loaded in this order:
8//! 1. A [`RawLibrary`] is loaded
9//! (The library is leaked so that the root module loader can
10//! do anything incompatible with library unloading.)
11//! 2. An [`AbiHeaderRef`] handle to the static that contains the root module is obtained.
12//! 3. The [`AbiHeaderRef`] checks that the abi_stable version used by that library is
13//! compatible with the loader's, upgrading to a [`&'static LibHeader`] on success.
14//! 4. The [`LibHeader`] checks that the layout of the types in the root module
15//! (and everything it references) are compatible with the loader's
16//! 5. The [root module](./trait.RootModule.html)
17//! is loaded using the function from the loaded library
18//! that was annotated with [`#[export_root_module]`](../attr.export_root_module.html).
19//! 6. [`RootModule::initialize`] is called on the root module.
20//!
21//! All steps can return errors.
22//!
23//! [`RawLibrary`]: ./struct.RawLibrary.html
24//! [`AbiHeaderRef`]: ./struct.AbiHeaderRef.html
25//! [`RootModule`]: ./trait.RootModule.html
26//! [`RootModule::initialize`]: ./trait.RootModule.html#method.initialization
27//! [`&'static LibHeader`]: ./struct.LibHeader.html
28
29use std::{
30 convert::Infallible,
31 mem,
32 path::{Path, PathBuf},
33 sync::atomic,
34};
35
36#[allow(unused_imports)]
37use core_extensions::SelfOps;
38
39use libloading::{Library as LibLoadingLibrary, Symbol as LLSymbol};
40
41use crate::{
42 abi_stability::stable_abi_trait::StableAbi,
43 globals::{self, Globals},
44 marker_type::ErasedPrefix,
45 prefix_type::{PrefixRef, PrefixRefTrait},
46 sabi_types::{LateStaticRef, NulStr, VersionNumber, VersionStrings},
47 std_types::{RResult, RStr},
48 type_layout::TypeLayout,
49};
50
51pub mod c_abi_testing;
52pub mod development_utils;
53mod errors;
54mod lib_header;
55
56#[cfg(test)]
57mod library_tests;
58
59mod raw_library;
60mod root_mod_trait;
61
62#[doc(no_inline)]
63pub use self::c_abi_testing::{CAbiTestingFns, C_ABI_TESTING_FNS};
64
65pub use self::{
66 errors::{IntoRootModuleResult, LibraryError, RootModuleError},
67 lib_header::{AbiHeader, AbiHeaderRef, LibHeader},
68 raw_library::RawLibrary,
69 root_mod_trait::{
70 abi_header_from_path, abi_header_from_raw_library, lib_header_from_path,
71 lib_header_from_raw_library, RootModule, RootModuleConsts,
72 },
73};
74
75///////////////////////////////////////////////////////////////////////////////
76
77/// What naming convention to expect when loading a library from a directory.
78#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
79pub enum LibrarySuffix {
80 /// Loads a dynamic library at `<folder>/<name>.extension`
81 NoSuffix,
82
83 /// Loads a dynamic library at `<folder>/<name>-<pointer_size>.<extension>`
84 Suffix,
85}
86
87//////////////////////////////////////////////////////////////////////
88
89/// The path a library is loaded from.
90#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
91pub enum LibraryPath<'a> {
92 /// The full path to the dynamic library.
93 FullPath(&'a Path),
94 /// The path to the directory that contains the dynamic library.
95 Directory(&'a Path),
96}
97
98//////////////////////////////////////////////////////////////////////
99
100/// Tells [`LibHeader::from_constructor`] whether to
101/// include the layout of the root module for checking it when loaded.
102pub enum CheckTypeLayout {
103 /// Include the layout of the root module
104 Yes,
105 /// Exclude the layout of the root module
106 No,
107}
108
109//////////////////////////////////////////////////////////////////////
110
111/// Whether the ABI of a root module is checked.
112#[repr(u8)]
113#[derive(Debug, Copy, Clone, StableAbi)]
114pub enum IsLayoutChecked {
115 /// The ABI is checked
116 Yes(&'static TypeLayout),
117 /// The ABI is not checked
118 No,
119}
120
121impl IsLayoutChecked {
122 /// Converts this into an `Option`.
123 ///
124 /// `Ỳes` corresponds to `Some`, and `No` corresponds to `None`.
125 pub const fn into_option(self) -> Option<&'static TypeLayout> {
126 match self {
127 IsLayoutChecked::Yes(x) => Some(x),
128 IsLayoutChecked::No => None,
129 }
130 }
131}
132
133//////////////////////////////////////////////////////////////////////
134
135/// The return type of the function that the
136/// [`#[export_root_module]`](../attr.export_root_module.html) attribute outputs.
137pub type RootModuleResult = RResult<PrefixRef<ErasedPrefix>, RootModuleError>;
138
139//////////////////////////////////////////////////////////////////////
140
141/// The static variables declared for some [`RootModule`] implementor.
142/// [`RootModule`]: ./trait.RootModule.html
143#[doc(hidden)]
144pub struct RootModuleStatics<M> {
145 root_mod: LateStaticRef<M>,
146 raw_lib: LateStaticRef<&'static RawLibrary>,
147}
148
149impl<M> RootModuleStatics<M> {
150 ///
151 /// # Safety
152 ///
153 /// This must only be called from the `abi_stable::declare_root_module_statics` macro.
154 #[doc(hidden)]
155 #[inline]
156 pub const unsafe fn __private_new() -> Self {
157 Self {
158 root_mod: LateStaticRef::new(),
159 raw_lib: LateStaticRef::new(),
160 }
161 }
162}
163
164/// Implements the [`RootModule::root_module_statics`] associated function.
165///
166/// To define the associated function use:
167/// `abi_stable::declare_root_module_statics!{TypeOfSelf}`.
168/// Passing `Self` instead of `TypeOfSelf` won't work.
169///
170/// # Example
171///
172/// ```rust
173/// use abi_stable::{
174/// library::RootModule,
175/// sabi_types::VersionStrings,
176/// StableAbi,
177/// };
178///
179/// #[repr(C)]
180/// #[derive(StableAbi)]
181/// #[sabi(kind(Prefix(prefix_ref = Module_Ref, prefix_fields = Module_Prefix)))]
182/// pub struct Module{
183/// pub first: u8,
184/// #[sabi(last_prefix_field)]
185/// pub second: u16,
186/// pub third: u32,
187/// }
188/// impl RootModule for Module_Ref {
189/// abi_stable::declare_root_module_statics!{Module_Ref}
190/// const BASE_NAME: &'static str = "example_root_module";
191/// const NAME: &'static str = "example_root_module";
192/// const VERSION_STRINGS: VersionStrings = abi_stable::package_version_strings!();
193/// }
194///
195/// # fn main(){}
196/// ```
197///
198#[cfg_attr(
199 doctest,
200 doc = r###"
201
202```rust
203struct Foo;
204impl Foo {
205 abi_stable::declare_root_module_statics!{Foo}
206}
207```
208
209```rust
210struct Foo;
211impl Foo {
212 abi_stable::declare_root_module_statics!{(Foo)}
213}
214```
215
216```compile_fail
217struct Foo;
218impl Foo {
219 abi_stable::declare_root_module_statics!{Self}
220}
221```
222
223```compile_fail
224struct Foo;
225impl Foo {
226 abi_stable::declare_root_module_statics!{(Self)}
227}
228```
229
230```compile_fail
231struct Foo;
232impl Foo {
233 abi_stable::declare_root_module_statics!{((Self))}
234}
235```
236
237"###
238)]
239/// [`RootModule::root_module_statics`]:
240/// ./library/trait.RootModule.html#tymethod.root_module_statics
241#[macro_export]
242macro_rules! declare_root_module_statics {
243 ( ( $($stuff:tt)* ) ) => (
244 $crate::declare_root_module_statics!{$($stuff)*}
245 );
246 ( Self ) => (
247 compile_error!{"Don't use `Self`, write the full type name"}
248 );
249 ( $this:ty ) => (
250 #[inline]
251 fn root_module_statics()->&'static $crate::library::RootModuleStatics<$this>{
252 static _ROOT_MOD_STATICS:$crate::library::RootModuleStatics<$this>= unsafe{
253 $crate::library::RootModuleStatics::__private_new()
254 };
255
256 &_ROOT_MOD_STATICS
257 }
258 );
259}
260
261//////////////////////////////////////////////////////////////////////
262
263abi_stable_derive::__const_mangled_root_module_loader_name! {}
264
265/// The name of the `static` that contains the [`LibHeader`] of an abi_stable library.
266///
267/// There's also these alternatives to this constant:
268/// - [`ROOT_MODULE_LOADER_NAME_WITH_NUL`]: this constant concatenated with `"\0"`
269/// - [`ROOT_MODULE_LOADER_NAME_NULSTR`]: a [`NulStr`] equivalent of this constant
270///
271/// [`LibHeader`]: ./struct.LibHeader.html
272/// [`AbiHeaderRef`]: ./struct.AbiHeaderRef.html
273/// [`AbiHeaderRef::upgrade`]: ./struct.AbiHeaderRef.html#method.upgrade
274/// [`ROOT_MODULE_LOADER_NAME_WITH_NUL`]: ./constant.ROOT_MODULE_LOADER_NAME_WITH_NUL.html
275/// [`ROOT_MODULE_LOADER_NAME_NULSTR`]: ./constant.ROOT_MODULE_LOADER_NAME_NULSTR.html
276/// [`NulStr`]: ../sabi_types/struct.NulStr.html
277pub const ROOT_MODULE_LOADER_NAME: &str = PRIV_MANGLED_ROOT_MODULE_LOADER_NAME;
278
279/// A nul-terminated equivalent of [`ROOT_MODULE_LOADER_NAME`].
280///
281/// [`ROOT_MODULE_LOADER_NAME`]: ./constant.ROOT_MODULE_LOADER_NAME.html
282pub const ROOT_MODULE_LOADER_NAME_WITH_NUL: &str = PRIV_MANGLED_ROOT_MODULE_LOADER_NAME_NUL;
283
284/// A [`NulStr`] equivalent of [`ROOT_MODULE_LOADER_NAME`].
285///
286/// [`ROOT_MODULE_LOADER_NAME`]: ./constant.ROOT_MODULE_LOADER_NAME.html
287/// [`NulStr`]: ../sabi_types/struct.NulStr.html
288pub const ROOT_MODULE_LOADER_NAME_NULSTR: NulStr<'_> =
289 NulStr::from_str(PRIV_MANGLED_ROOT_MODULE_LOADER_NAME_NUL);
290
291//////////////////////////////////////////////////////////////////////
292
293#[doc(hidden)]
294pub fn __call_root_module_loader<T>(function: fn() -> T) -> RootModuleResult
295where
296 T: IntoRootModuleResult,
297{
298 type TheResult = Result<PrefixRef<ErasedPrefix>, RootModuleError>;
299 let res = ::std::panic::catch_unwind(|| -> TheResult {
300 let ret: T::Module = function().into_root_module_result()?;
301
302 let _ = <T::Module as RootModule>::load_module_with(|| Ok::<_, Infallible>(ret));
303 unsafe { ret.to_prefix_ref().cast::<ErasedPrefix>().piped(Ok) }
304 });
305 // We turn an unwinding panic into an error value
306 let flattened: TheResult = res.unwrap_or(Err(RootModuleError::Unwound));
307 RootModuleResult::from(flattened)
308}