1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// Copyright (c) 2023 Jonathan "Razordor" Alan Thomason
//! This macro is designed to make loading functions from `.dll`s, and `.so` files easy and convenient.
//! `dylink` can make use of the configuration predicate `any`, which can be used to fallback to alternative shared libraries as needed.
//!
//! # General Example
//! ```rust
//! use dylink::dylink;
//!
//! #[dylink(name = "Kernel32.dll")]
//! extern "system" {
//! fn GetLastError() -> u32;
//! }
//! ```
//!
//! # Vulkan Specialization
//! There is also a builtin vulkan loader option in the macro as well, which automatically looks for the shared library where expected.
//! The appropriate ABI to use with the vulkan loader is `extern "system"`. Unlike generalized loading, the vulkan specialization loads
//! functions indirectly through `vkGetInstanceProcAddr`, and when applicable `vkGetDeviceProcAddr`, to retrieve vulkan addresses properly.
//! The internal copies of the instance and device handles are only stored until destroyed through a dylink generated vulkan function.
//!
//! *Note: Due to how dylink handles loading, `vkCreateInstance`, `vkDestroyInstance`, `vkCreateDevice`, and `vkDestroyDevice` are
//! incompatible with the `strip=true` macro argument.*
//! ```rust
//! use dylink::dylink;
//!
//! # type VkInstanceCreateInfo = std::ffi::c_void;
//! # type VkAllocationCallbacks = std::ffi::c_void;
//! # type VkInstance = std::ffi::c_void;
//! # type VkResult = i32;
//! #[dylink(vulkan)]
//! extern "system" {
//! fn vkCreateInstance(
//! pCreateInfo: *const VkInstanceCreateInfo,
//! pAllocator: *const VkAllocationCallbacks,
//! pInstance: *mut VkInstance,
//! ) -> VkResult;
//! }
//! ```
//!
//! # Configuration Predicates
//! Dylink can also accept predicated disjunctions in an idiomatic manner by making use of the `any` function.
//! `any()` uses short-circuit logic to check for the existance of shared libraries.
//! ```rust
//! # use dylink::dylink;
//! #[dylink(any(name = "example_lib.so", name = "example_lib.so.1"))]
//! extern "C" {
//! fn my_function();
//! }
//! ```
//!
//! # Checking for Libraries
//! The greatest strength in dynamically linking at run-time is the ability to recover when libraries are missing.
//! This can even include when all libraries in the configuration predicate mentioned above fails. To handle this
//! problem dylink provides a `strip` argument that you can use with the macro to strip the abstraction and
//! leverage the underlying static variable's member functions.
//!
//! *Note: Stripping the abstraction does not necessarily make it cheaper, because dylink is designed to inline the abstraction for you.*
//! ```rust
//! # use dylink::dylink;
//! #[dylink(name = "example.so", strip=true)]
//! extern "C" {
//! fn my_function();
//! }
//!
//! fn main() {
//! match my_function.try_link() {
//! Ok(function) => unsafe {function()},
//! Err(reason) => println!("{reason}"),
//! }
//! }
//! ```
//!
//! The `strip` argument as mentioned above has an unfortunate caveat of not being documentation friendly and cannot be freely
//! passed around as a function pointer since the function will use the `LazyFn` wrapper, which is the fundemental type of the
//! dylink crate. Although stripped abstractions cannot be passed around like `fn` pointers they can still be called like one.
//! However, without explicitly checking if the library exists at any point, it may still panic with an appropriate error
//! message if the library is really missing.
//! ```should_panic
//! # use dylink::dylink;
//! #[dylink(name = "missing_library.dll", strip=true)]
//! extern "C" {
//! fn my_function();
//! }
//!
//! fn main() {
//! unsafe { my_function() } // panics since the library is missing
//! }
//! ```
//!
//! # About Library Unloading
//! Shared library unloading is extremely cursed, always unsafe, and we don't even try to support it.
//! Unloading a library means not only are all loaded dylink functions invalidated, but functions loaded from **ALL**
//! crates in the project are also invalidated, which will immediately lead to segfaults... a lot of them.
use ;
use Lazy;
use ffi;
pub use *;
pub use *;
pub use ;
/// Macro for generating dynamically linked functions procedurally.
///
/// Refer to crate level documentation for more information.
pub use dylink;
;
// I don't know how to implement wasm, so I'll just drop this here...
compile_error!;
// These globals are read every time a vulkan function is called for the first time,
// which occurs through `LazyFn::link`.
static VK_INSTANCE: RwLock =
new;
static VK_DEVICE: RwLock =
new;
// Used as a placeholder function pointer. This should **NEVER** be called directly,
// and promptly cast into the correct function pointer type.
pub type FnPtr = unsafe extern "system" fn ;
// The result of a dylink function
pub type Result<T> = Result;
// TODO: Make the `Global` struct below public when extern types are stable.
// The name `Global` is still TBD.
/// The global context for specializations.
///
/// This implicitly controls how the specialization `#[dylink(vulkan)]` handles function loading.
/// This Global is injected when building specializations, but is excluded when building generalizations,
/// such as `#[dylink(name = "my_lib.so")]`.
;
/// Opaque pointer sized library handle
pub ;
unsafe
unsafe
pub