Skip to main content

dtor/
lib.rs

1#![recursion_limit = "256"]
2#![no_std]
3#![doc = include_str!("../docs/BUILD.md")]
4//! # dtor
5#![doc = include_str!("../docs/PREAMBLE.md")]
6#![doc = include_str!("../docs/GENERATED.md")]
7
8#[cfg(feature = "std")]
9extern crate std;
10
11mod macros;
12mod native;
13mod parse;
14
15pub use native::*;
16
17/// Marks a function as a library/executable destructor. This uses OS-specific
18/// linker sections to call a specific function at termination time.
19///
20/// Multiple shutdown functions are supported, but the invocation order is not
21/// guaranteed.
22///
23/// ```rust,ignore
24/// # #![cfg_attr(feature="used_linker", feature(used_with_arg))]
25/// # use dtor::dtor;
26/// # fn main() {}
27///
28/// #[dtor]
29/// fn shutdown() {
30///   /* ... */
31/// }
32/// ```
33#[doc(inline)]
34#[cfg(feature = "proc_macro")]
35pub use dtor_proc_macro::dtor;
36
37#[doc(hidden)]
38#[cfg(feature = "proc_macro")]
39pub use dtor_proc_macro::__dtor_from_ctor;
40
41/// Declarative forms of the `#[dtor]` macro.
42///
43/// The declarative forms wrap and parse a proc_macro-like syntax like so, and
44/// are identical in expansion to the undecorated procedural macros. The
45/// declarative forms support the same attribute parameters as the procedural
46/// macros.
47///
48/// ```rust
49/// # #[cfg(any())] mod test { use dtor::*; use libc_print::*;
50/// dtor::declarative::dtor! {
51///   #[dtor]
52///   fn foo() {
53///     libc_println!("Goodbye, world!");
54///   }
55/// }
56/// # }
57///
58/// // ... the above is identical to:
59///
60/// # #[cfg(any())] mod test_2 { use dtor::*; use libc_print::*;
61/// #[dtor]
62/// fn foo() {
63///   libc_println!("Goodbye, world!");
64/// }
65/// # }
66/// ```
67pub mod declarative {
68    #[doc(inline)]
69    pub use crate::__dtor_parse as dtor;
70}
71
72#[doc(hidden)]
73#[allow(unused)]
74pub mod __support {
75    use crate::macros::*;
76
77    // Required for proc_macro.
78    pub use crate::__dtor_parse as dtor_parse;
79
80    pub use crate::native::*;
81}
82
83__declare_features!(
84    dtor: __dtor_features;
85
86    /// Make the ctor function anonymous.
87    anonymous {
88        attr: [(anonymous) => (anonymous)];
89    };
90    /// Specify a custom crate path for the `dtor` crate. Used when re-exporting the dtor macro.
91    crate_path {
92        attr: [(crate_path = $path:pat) => (($path))];
93        example: "crate_path = ::path::to::dtor::crate";
94    };
95    /// Specify a custom export name prefix for the constructor function.
96    ///
97    /// If specified, an export with the given prefix will be generated in the form:
98    ///
99    /// `<prefix>_<unique_id>`
100    ctor_export_name_prefix {
101        attr: [(ctor(export_name_prefix = $ctor_export_name_prefix_str:literal)) => ($ctor_export_name_prefix_str)];
102        example: "ctor(export_name_prefix = \"ctor_\")";
103        default {
104            (target_os = "aix") => "__sinit80000000",
105            _ => (),
106        }
107    };
108    /// Place the initialization function pointer in a custom link section.
109    ctor_link_section {
110        attr: [(ctor(link_section = $ctor_link_section_name:literal)) => ($ctor_link_section_name)];
111        example: "ctor(link_section = \".ctors\")";
112        default {
113            // This is no longer supported by Apple
114            (target_vendor = "apple") => "__DATA,__mod_init_func,mod_init_funcs",
115            // Most LLVM/GCC targets can use .fini_array
116            (any(
117                target_os = "linux",
118                target_os = "android",
119                target_os = "freebsd",
120                target_os = "netbsd",
121                target_os = "openbsd",
122                target_os = "dragonfly",
123                target_os = "illumos",
124                target_os = "haiku",
125                target_os = "vxworks",
126                target_os = "nto",
127                target_family = "wasm"
128            )) => ".init_array",
129            // No OS
130            (target_os = "none") => ".init_array",
131            // xtensa targets: .dtors
132            (target_arch = "xtensa") => ".ctors",
133            // Windows targets: .CRT$XCU
134            (all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc"))) => ".CRT$XCU",
135            // ... except GNU
136            (all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc")))) => ".ctors",
137            (all(target_os = "aix")) => (), // AIX uses export_name_prefix
138            _ => (compile_error!("Unsupported target for #[ctor]"))
139        }
140    };
141    /// The default method used for running a `dtor` on termination. This is
142    /// generally not recommended as code may be unloaded before the dtor is
143    /// called.
144    ///
145    /// This is only used if the specified `dtor` method is `term`.
146    ///
147    /// All platforms use `at_binary_exit` except Windows, which uses
148    /// `at_module_exit`.
149    default_term_method {
150        default {
151            (target_vendor = "pc") => at_module_exit,
152            _ => at_binary_exit,
153        }
154    };
155    /// The default method used for running a `dtor` on module unload.
156    ///
157    /// This is only used if the `method` attribute is not specified, or if the
158    /// method is `unload`.
159    default_unload_method {
160        default {
161            _ => at_module_exit,
162        }
163    };
164    /// Specify a custom export name prefix for the destructor function.
165    ///
166    /// If specified, an export with the given prefix will be generated in the form:
167    ///
168    /// `<prefix>_<unique_id>`
169    export_name_prefix {
170        attr: [(export_name_prefix = $export_name_prefix_str:literal) => ($export_name_prefix_str)];
171        example: "export_name_prefix = \"ctor_\"";
172        default {
173            (target_os = "aix") => "__sterm80000000",
174            _ => (),
175        }
176    };
177    /// Place the destructor function pointer in a custom link section.
178    link_section {
179        attr: [(link_section = $section:literal) => ($section)];
180        example: "link_section = \".dtors\"";
181        default {
182            // This is no longer supported by Apple
183            (target_vendor = "apple") => "__DATA,__mod_term_func,mod_term_funcs",
184            // Most LLVM/GCC targets can use .fini_array
185            (any(
186                target_os = "linux",
187                target_os = "android",
188                target_os = "freebsd",
189                target_os = "netbsd",
190                target_os = "openbsd",
191                target_os = "dragonfly",
192                target_os = "illumos",
193                target_os = "haiku",
194                target_os = "vxworks",
195                target_os = "nto",
196                target_family = "wasm"
197            )) => ".fini_array",
198            // No OS
199            (target_os = "none") => ".fini_array",
200            // xtensa targets: .dtors
201            (target_arch = "xtensa") => ".dtors",
202            // Windows targets: .CRT$XPU (requires static CRT)
203            (all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc"))) => ".CRT$XPU",
204            // ... except GNU
205            (all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc")))) => ".dtors",
206            (all(target_os = "aix")) => (), // AIX uses export_name_prefix
207            _ => (compile_error!("Unsupported target for #[dtor]"))
208        }
209    };
210    /// Specify the dtor method.
211    ///
212    ///  - `term`: Run the dtor on binary termination using the platform's
213    ///    [default_term_method](#default_term_method). Not recommended as code
214    ///    may be unloaded before the dtor is called.
215    ///  - `unload`: Run the dtor on module unload (library or binary) using the
216    ///    platform's [default_unload_method](#default_unload_method).
217    ///  - `at_module_exit`: Run the dtor using the platform's
218    ///    [`at_module_exit`][at_module_exit] (`__cxa_atexit` on all platforms
219    ///    other than Windows, `atexit` on Windows).
220    ///  - `at_binary_exit`: Run the dtor using the platform's
221    ///    [`at_binary_exit`][at_binary_exit] (unsupported on Windows
222    ///    platforms).
223    ///  - `linker`: Register the dtor using the platform's
224    ///    [link_section](#link_section) or
225    ///    [export_name_prefix](#export_name_prefix) (unsupported on Apple
226    ///    platforms).
227    ///
228    /// [at_module_exit]: crate::native::at_module_exit
229    /// [at_binary_exit]: crate::native::at_binary_exit
230    method {
231        attr: [(method = $method_id:ident) => ($method_id)];
232        example: "method = term|unload|at_module_exit|at_binary_exit|linker";
233        validate: [(method = term), (method = unload), (method = at_module_exit), (method = at_binary_exit), (method = linker)];
234        default {
235            (target_vendor = "apple") => at_module_exit,
236            (target_vendor = "pc") => at_module_exit,
237            _ => linker,
238        }
239    };
240    no_warn_on_missing_unsafe {
241        /// crate
242        /// Do not warn when a ctor or dtor is missing the `unsafe` keyword.
243        feature: "no_warn_on_missing_unsafe";
244        /// attr
245        /// Marks a ctor/dtor as unsafe.
246        attr: [(unsafe) => (no_warn_on_missing_unsafe)];
247    };
248    /// Enable support for the proc-macro `#[dtor]` attribute. The declarative
249    /// form (`dtor!(...)`) is always available. It is recommended that crates
250    /// re-exporting the `dtor` macro disable this feature and only use the
251    /// declarative form.
252    proc_macro {
253        feature: "proc_macro";
254    };
255    /// Enable support for the standard library.
256    std {
257        feature: "std";
258    };
259    used_linker {
260        /// crate
261        /// Applies `used(linker)` to all `dtor`-generated functions. Requires nightly and `feature(used_with_arg)`.
262        feature: "used_linker";
263        /// attr
264        /// Mark generated functions for this `dtor` as `used(linker)`. Requires nightly and `feature(used_with_arg)`.
265        attr: [(used(linker)) => (used_linker)];
266    };
267);
268
269#[cfg(doc)]
270__generate_docs!(__dtor_features);