ctor/
lib.rs

1//! Procedural macro for defining global constructor/destructor functions.
2//!
3//! This provides module initialization/teardown functions for Rust (like
4//! `__attribute__((constructor))` in C/C++) for Linux, OSX, and Windows via
5//! the `#[ctor]` and `#[dtor]` macros.
6//!
7//! This library works and is regularly tested on Linux, OSX and Windows, with both `+crt-static` and `-crt-static`.
8//! Other platforms are supported but not tested as part of the automatic builds. This library will also work as expected in both
9//! `bin` and `cdylib` outputs, ie: the `ctor` and `dtor` will run at executable or library
10//! startup/shutdown respectively.
11//!
12//! This library currently requires Rust > `1.31.0` at a minimum for the
13//! procedural macro support.
14
15#![recursion_limit = "256"]
16
17#[doc(hidden)]
18#[allow(unused)]
19pub use macros::__support;
20
21mod macros;
22
23/// Declarative forms of the `#[ctor]` and `#[dtor]` macros.
24///
25/// The declarative forms wrap and parse a proc_macro-like syntax like so, and
26/// are identical in expansion to the undecorated procedural macros. The
27/// declarative forms support the same attribute parameters as the procedural
28/// macros.
29///
30/// ```rust
31/// # mod test { use ctor::*; use libc_print::*;
32/// ctor::declarative::ctor! {
33///   #[ctor]
34///   fn foo() {
35///     libc_println!("Hello, world!");
36///   }
37/// }
38/// # }
39///
40/// // ... the above is identical to:
41///
42/// # mod test_2 { use ctor::*; use libc_print::*;
43/// #[ctor]
44/// fn foo() {
45///   libc_println!("Hello, world!");
46/// }
47/// # }
48/// ```
49pub mod declarative {
50    #[doc(inline)]
51    pub use crate::__support::ctor_parse as ctor;
52    #[doc(inline)]
53    #[cfg(feature = "dtor")]
54    pub use crate::__support::dtor_parse as dtor;
55}
56
57/// Marks a function or static variable as a library/executable constructor.
58/// This uses OS-specific linker sections to call a specific function at load
59/// time.
60///
61/// # Important notes
62///
63/// Rust does not make any guarantees about stdlib support for life-before or
64/// life-after main. This means that the `ctor` crate may not work as expected
65/// in some cases, such as when used in an `async` runtime or making use of
66/// stdlib services.
67///
68/// Multiple startup functions/statics are supported, but the invocation order
69/// is not guaranteed.
70///
71/// The `ctor` crate assumes it is available as a direct dependency, with
72/// `extern crate ctor`. If you re-export `ctor` items as part of your crate,
73/// you can use the `crate_path` parameter to redirect the macro's output to the
74/// correct crate.
75///
76/// # Attribute parameters
77///
78///  - `crate_path = ::path::to::ctor::crate`: The path to the `ctor` crate
79///    containing the support macros. If you re-export `ctor` items as part of
80///    your crate, you can use this to redirect the macro's output to the
81///    correct crate.
82///  - `used(linker)`: (Advanced) Mark the function as being used in the link
83///    phase.
84///  - `link_section = "section"`: The section to place the constructor in.
85///  - `anonymous`: Do not give the constructor a name in the generated code
86///    (allows for multiple constructors with the same name).
87///
88/// # Examples
89///
90/// Print a startup message (using `libc_print` for safety):
91///
92/// ```rust
93/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
94/// # extern crate ctor;
95/// # use ctor::*;
96/// use libc_print::std_name::println;
97///
98/// #[ctor]
99/// unsafe fn foo() {
100///   // Using libc_print which is safe in `#[ctor]`
101///   println!("Hello, world!");
102/// }
103///
104/// # fn main() {
105/// println!("main()");
106/// # }
107/// ```
108///
109/// Make changes to `static` variables:
110///
111/// ```rust
112/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
113/// # extern crate ctor;
114/// # mod test {
115/// # use ctor::*;
116/// # use std::sync::atomic::{AtomicBool, Ordering};
117/// static INITED: AtomicBool = AtomicBool::new(false);
118///
119/// #[ctor]
120/// unsafe fn set_inited() {
121///   INITED.store(true, Ordering::SeqCst);
122/// }
123/// # }
124/// ```
125///
126/// Initialize a `HashMap` at startup time:
127///
128/// ```rust
129/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
130/// # extern crate ctor;
131/// # mod test {
132/// # use std::collections::HashMap;
133/// # use ctor::*;
134/// #[ctor]
135/// pub static STATIC_CTOR: HashMap<u32, String> = unsafe {
136///   let mut m = HashMap::new();
137///   for i in 0..100 {
138///     m.insert(i, format!("x*100={}", i*100));
139///   }
140///   m
141/// };
142/// # }
143/// # pub fn main() {
144/// #   assert_eq!(test::STATIC_CTOR.len(), 100);
145/// #   assert_eq!(test::STATIC_CTOR[&20], "x*100=2000");
146/// # }
147/// ```
148///
149/// # Details
150///
151/// The `#[ctor]` macro makes use of linker sections to ensure that a function
152/// is run at startup time.
153///
154/// ```rust
155/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
156/// # extern crate ctor;
157/// # mod test {
158/// # use ctor::*;
159/// #[ctor]
160///
161/// unsafe fn my_init_fn() {
162///   /* ... */
163/// }
164/// # }
165/// ```
166///
167/// The above example translates into the following Rust code (approximately):
168///
169/// ```rust
170/// # fn my_init_fn() {}
171/// #[used]
172/// #[cfg_attr(target_os = "linux", link_section = ".init_array")]
173/// #[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func")]
174/// #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
175/// /* ... other platforms elided ... */
176/// static INIT_FN: extern fn() = {
177///     extern fn init_fn() { my_init_fn(); };
178///     init_fn
179/// };
180/// ```
181///
182/// For `static` items, the macro generates a `std::sync::OnceLock` that is
183/// initialized at startup time.
184///
185/// ```rust
186/// # extern crate ctor;
187/// # mod test {
188/// # use ctor::*;
189/// # use std::collections::HashMap;
190/// #[ctor]
191/// static FOO: HashMap<u32, String> = unsafe {
192///   let mut m = HashMap::new();
193///   for i in 0..100 {
194///     m.insert(i, format!("x*100={}", i*100));
195///   }
196///   m
197/// };
198/// # }
199/// ```
200///
201/// The above example translates into the following Rust code (approximately),
202/// which eagerly initializes the `HashMap` inside a `OnceLock` at startup time:
203///
204/// ```rust
205/// # extern crate ctor;
206/// # mod test {
207/// # use ctor::ctor;
208/// # use std::collections::HashMap;
209/// static FOO: FooStatic = FooStatic { value: ::std::sync::OnceLock::new() };
210/// struct FooStatic {
211///   value: ::std::sync::OnceLock<HashMap<u32, String>>,
212/// }
213///
214/// impl ::std::ops::Deref for FooStatic {
215///   type Target = HashMap<u32, String>;
216///   fn deref(&self) -> &Self::Target {
217///     self.value.get_or_init(|| unsafe {
218///       let mut m = HashMap::new();
219///       for i in 0..100 {
220///         m.insert(i, format!("x*100={}", i*100));
221///       }
222///       m
223///     })
224///   }
225/// }
226///
227/// #[ctor]
228/// unsafe fn init_foo_ctor() {
229///   _ = &*FOO;
230/// }
231/// # }
232/// ```
233#[doc(inline)]
234#[cfg(feature = "proc_macro")]
235pub use ctor_proc_macro::ctor;
236
237/// Re-exported `#[dtor]` proc-macro from `dtor` crate.
238///
239/// See [`::dtor`] for more details.
240#[doc(inline)]
241#[cfg(feature = "dtor")]
242pub use dtor::__dtor_from_ctor as dtor;