-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathlib.rs
242 lines (236 loc) · 6.83 KB
/
lib.rs
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! Procedural macro for defining global constructor/destructor functions.
//!
//! This provides module initialization/teardown functions for Rust (like
//! `__attribute__((constructor))` in C/C++) for Linux, OSX, and Windows via
//! the `#[ctor]` and `#[dtor]` macros.
//!
//! This library works and is regularly tested on Linux, OSX and Windows, with both `+crt-static` and `-crt-static`.
//! Other platforms are supported but not tested as part of the automatic builds. This library will also work as expected in both
//! `bin` and `cdylib` outputs, ie: the `ctor` and `dtor` will run at executable or library
//! startup/shutdown respectively.
//!
//! This library currently requires Rust > `1.31.0` at a minimum for the
//! procedural macro support.
#![recursion_limit = "256"]
#[doc(hidden)]
#[allow(unused)]
pub use macros::__support;
mod macros;
/// Declarative forms of the `#[ctor]` and `#[dtor]` macros.
///
/// The declarative forms wrap and parse a proc_macro-like syntax like so, and
/// are identical in expansion to the undecorated procedural macros. The
/// declarative forms support the same attribute parameters as the procedural
/// macros.
///
/// ```rust
/// # mod test { use ctor::*; use libc_print::*;
/// ctor::declarative::ctor! {
/// #[ctor]
/// fn foo() {
/// libc_println!("Hello, world!");
/// }
/// }
/// # }
///
/// // ... the above is identical to:
///
/// # mod test_2 { use ctor::*; use libc_print::*;
/// #[ctor]
/// fn foo() {
/// libc_println!("Hello, world!");
/// }
/// # }
/// ```
pub mod declarative {
#[doc(inline)]
pub use crate::__support::ctor_parse as ctor;
#[doc(inline)]
#[cfg(feature = "dtor")]
pub use crate::__support::dtor_parse as dtor;
}
/// Marks a function or static variable as a library/executable constructor.
/// This uses OS-specific linker sections to call a specific function at load
/// time.
///
/// # Important notes
///
/// Rust does not make any guarantees about stdlib support for life-before or
/// life-after main. This means that the `ctor` crate may not work as expected
/// in some cases, such as when used in an `async` runtime or making use of
/// stdlib services.
///
/// Multiple startup functions/statics are supported, but the invocation order
/// is not guaranteed.
///
/// The `ctor` crate assumes it is available as a direct dependency, with
/// `extern crate ctor`. If you re-export `ctor` items as part of your crate,
/// you can use the `crate_path` parameter to redirect the macro's output to the
/// correct crate.
///
/// # Attribute parameters
///
/// - `crate_path = ::path::to::ctor::crate`: The path to the `ctor` crate
/// containing the support macros. If you re-export `ctor` items as part of
/// your crate, you can use this to redirect the macro's output to the
/// correct crate.
/// - `used(linker)`: (Advanced) Mark the function as being used in the link
/// phase.
/// - `link_section = "section"`: The section to place the constructor in.
/// - `anonymous`: Do not give the constructor a name in the generated code
/// (allows for multiple constructors with the same name).
///
/// # Examples
///
/// Print a startup message (using `libc_print` for safety):
///
/// ```rust
/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
/// # extern crate ctor;
/// # use ctor::*;
/// use libc_print::std_name::println;
///
/// #[ctor]
/// unsafe fn foo() {
/// // Using libc_print which is safe in `#[ctor]`
/// println!("Hello, world!");
/// }
///
/// # fn main() {
/// println!("main()");
/// # }
/// ```
///
/// Make changes to `static` variables:
///
/// ```rust
/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
/// # extern crate ctor;
/// # mod test {
/// # use ctor::*;
/// # use std::sync::atomic::{AtomicBool, Ordering};
/// static INITED: AtomicBool = AtomicBool::new(false);
///
/// #[ctor]
/// unsafe fn set_inited() {
/// INITED.store(true, Ordering::SeqCst);
/// }
/// # }
/// ```
///
/// Initialize a `HashMap` at startup time:
///
/// ```rust
/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
/// # extern crate ctor;
/// # mod test {
/// # use std::collections::HashMap;
/// # use ctor::*;
/// #[ctor]
/// pub static STATIC_CTOR: HashMap<u32, String> = unsafe {
/// let mut m = HashMap::new();
/// for i in 0..100 {
/// m.insert(i, format!("x*100={}", i*100));
/// }
/// m
/// };
/// # }
/// # pub fn main() {
/// # assert_eq!(test::STATIC_CTOR.len(), 100);
/// # assert_eq!(test::STATIC_CTOR[&20], "x*100=2000");
/// # }
/// ```
///
/// # Details
///
/// The `#[ctor]` macro makes use of linker sections to ensure that a function
/// is run at startup time.
///
/// ```rust
/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
/// # extern crate ctor;
/// # mod test {
/// # use ctor::*;
/// #[ctor]
///
/// unsafe fn my_init_fn() {
/// /* ... */
/// }
/// # }
/// ```
///
/// The above example translates into the following Rust code (approximately):
///
/// ```rust
/// # fn my_init_fn() {}
/// #[used]
/// #[cfg_attr(target_os = "linux", link_section = ".init_array")]
/// #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
/// #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
/// /* ... other platforms elided ... */
/// static INIT_FN: extern fn() = {
/// extern fn init_fn() { my_init_fn(); };
/// init_fn
/// };
/// ```
///
/// For `static` items, the macro generates a `std::sync::OnceLock` that is
/// initialized at startup time.
///
/// ```rust
/// # extern crate ctor;
/// # mod test {
/// # use ctor::*;
/// # use std::collections::HashMap;
/// #[ctor]
/// static FOO: HashMap<u32, String> = unsafe {
/// let mut m = HashMap::new();
/// for i in 0..100 {
/// m.insert(i, format!("x*100={}", i*100));
/// }
/// m
/// };
/// # }
/// ```
///
/// The above example translates into the following Rust code (approximately),
/// which eagerly initializes the `HashMap` inside a `OnceLock` at startup time:
///
/// ```rust
/// # extern crate ctor;
/// # mod test {
/// # use ctor::ctor;
/// # use std::collections::HashMap;
/// static FOO: FooStatic = FooStatic { value: ::std::sync::OnceLock::new() };
/// struct FooStatic {
/// value: ::std::sync::OnceLock<HashMap<u32, String>>,
/// }
///
/// impl ::std::ops::Deref for FooStatic {
/// type Target = HashMap<u32, String>;
/// fn deref(&self) -> &Self::Target {
/// self.value.get_or_init(|| unsafe {
/// let mut m = HashMap::new();
/// for i in 0..100 {
/// m.insert(i, format!("x*100={}", i*100));
/// }
/// m
/// })
/// }
/// }
///
/// #[ctor]
/// unsafe fn init_foo_ctor() {
/// _ = &*FOO;
/// }
/// # }
/// ```
#[doc(inline)]
#[cfg(feature = "proc_macro")]
pub use ctor_proc_macro::ctor;
/// Re-exported `#[dtor]` proc-macro from `dtor` crate.
///
/// See [`::dtor`] for more details.
#[doc(inline)]
#[cfg(feature = "dtor")]
pub use dtor::__dtor_from_ctor as dtor;