[go: up one dir, main page]

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