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