
The crate is part of the [`linktime`](https://crates.io/crates/linktime) project.
| `linktime` | [](https://docs.rs/linktime) | [](https://crates.io/crates/linktime) |
| `ctor` | [](https://docs.rs/ctor) | [](https://crates.io/crates/ctor) |
| `dtor` | [](https://docs.rs/dtor) | [](https://crates.io/crates/dtor) |
| `link-section` | [](https://docs.rs/link-section) | [](https://crates.io/crates/link-section) |
# dtor
Shutdown functions for Rust (like `__attribute__((destructor))` in C/C++) for
Linux, macOS, Windows, mobile (iOS/Android), WASM, BSD/BSD-likes and many other
platforms.
```rust
use dtor::dtor;
use libc_print::*;
#[dtor(unsafe)]
fn foo() {
libc_println!("Life after main!");
}
```
# Examples
Print a message at shutdown time.
```rust
#[dtor(unsafe)]
fn shutdown() {
// Using println! or eprintln! here may panic as Rust may have
// shut down some stdlib services at this time.
libc_println!("Shutting down!");
}
```
# Platform Support
| Linux | `.fini_array` | Yes (`atexit`) | Yes (`__cxa_atexit`) |
| macOS | `.mod_term_func` <sup><sup>π</sup></sup> | Yes (`atexit`) | Yes (`__cxa_atexit`) |
| Windows | `.CRT$XPU` <sup><sup>πͺ</sup></sup> | No | Yes (`atexit`) |
| WASM πΈοΈ | No | Yes | No |
| AIX | "Kind of" <sup><sup>π΅</sup></sup> | Yes | Yes |
| Other POSIX-like platforms | `.fini_array`/`.dtors` | Yes (`atexit`) | Yes (`__cxa_atexit`) |
Notes:
- <sup><sup>π</sup></sup> Not recommended. Apple platforms no longer call
`mod_term_func` functions.
- <sup><sup>πͺ</sup></sup> Not recommended. Windows platforms may not reliably
call functions in link sections, unless a binary is built with a static CRT.
- <sup><sup>π΅</sup></sup> Link sections are not supported on AIX, but the
platform calls functions with the prefix `__sinit` and `__sterm` at startup
and shutdown respectively. `__sterm`-prefixed functions are used when the
method is specified as `linker`.
- <sup><sup>πΈοΈ</sup></sup> WASM `wasm-unknown-unknown`, `wasm-wasip1`,
`wasm-wasip2` are supported.
- Rust does not currently allow linking into `.fini_array` sections on WASM,
regardless of target, so `at_binary_exit` is the only supported method on
all WASM targets.
- `wasm-unknown-unknown` requires host environment support for `atexit`.
- `wasm-wasip2` may require you to manually call `__wasm_call_ctors` and
`__wasm_call_dtors` at the appropriate times.
# Shutdown Method (`#[dtor(method = ...)]`)
The `#[dtor]` macro supports multiple registration strategies via
`#[dtor(method = ...)]`. The best choice is platform-dependent:
- `#[dtor]` (no method specified): Use the platform's most reliable method:
`at_module_exit` on Windows and Apple platforms, and `linker` on others.
- `unload`: Run on _module unload_ (library unload or process exit) using the
platform's default unload method.
- `term`: Run on _process termination only_ using the platform's default
termination method. Not recommended: code may be unloaded before the dtor
runs.
- `at_module_exit`: Register using `__cxa_atexit` (non-Windows) or `atexit`
(Windows) so the dtor runs when the module unloads. Unsupported on WASM.
- `at_binary_exit`: Register to run at process exit (unsupported on Windows).
- `linker`: Register using the platform's linker mechanism (`link_section` on
all platforms with the exception of `export_name_prefix` on AIX). Unsupported
on Apple platforms.
Default:
- Apple and Windows default to `at_module_exit`
- WASM defaults to `at_binary_exit` (note that you will need to provide your own
atexit implementation for `wasm32-unknown-unknown`)
- Most other platforms default to `linker`
Examples:
```rust
use dtor::dtor;
/// Use `at_module_exit` on all platforms
#[dtor(unsafe, method = at_module_exit)]
fn shutdown() {}
```
```rust
use dtor::dtor;
/// Use `link_section` with a section name of `.dtors` on most platforms,
/// and `export_name_prefix` on AIX.
///
/// Platform note: this will fail to compile on Apple platforms.
#[dtor(unsafe, method = linker, link_section = ".dtors")]
fn shutdown() {}
```
# Warnings
Rust's philosophy is that nothing happens before or after main and this library
explicitly subverts that. The code that runs in the `ctor` and `dtor` functions
should be careful to limit itself to `libc` functions and code that does not
rely on Rust's stdlib services.
See [`::life_before_main`](crate::life_before_main) for more information.
# Under the Hood
The `#[dtor]` macro effectively creates a constructor that calls `libc::atexit`
with the provided function, i.e. roughly equivalent to:
```rust,ignore
#[ctor]
fn dtor_atexit() {
libc::atexit(dtor);
}
```
# Crate Features
| `proc_macro` | Enable support for the proc-macro `#[dtor]` attribute. The declarative form (`dtor!(...)`) is always available. It is recommended that crates re-exporting the `dtor` macro disable this feature and only use the declarative form. |
| `std` | Enable support for the standard library. |
# Macro Attributes
<table><tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>anonymous</code></td><td>
Do not give the destructor's registration entry a name in the generated
code (allows for multiple items with the same name). Equivalent to
wrapping the registration in an anonymous const (i.e.: `const _ = { ... };`).
</td></tr>
<tr><td><code>crate_path = ::path::to::dtor::crate</code></td><td>
Specify a custom crate path for the `dtor` crate. Used when re-exporting the dtor macro.
</td></tr>
<tr><td><code>ctor(export_name_prefix = "ctor_")</code></td><td>
Specify a custom export name prefix for the generated constructor
function.
If specified, an export with the given prefix will be generated in the
form:
`<prefix>_<unique_id>`
</td></tr>
<tr><td><code>ctor(link_section = ".ctors")</code></td><td>
Place the generated registration constructor's function pointer in a
custom link section.
</td></tr>
<tr><td><code>export_name_prefix = "ctor_"</code></td><td>
Specify a custom export name prefix for the destructor function.
If specified, an export with the given prefix will be generated in the form:
`<prefix>_<unique_id>`
</td></tr>
<tr><td><code>link_section = ".dtors"</code></td><td>
Place the destructor function pointer in a custom link section.
</td></tr>
<tr><td><code>method = term|unload|at_module_exit|at_binary_exit|linker</code></td><td>
Specify the dtor method.
- `term`: Run the dtor on binary termination using the platform's
[default_term_method](#default_term_method). Not recommended as code
may be unloaded before the dtor is called.
- `unload`: Run the dtor on module unload (library or binary) using the
platform's [default_unload_method](#default_unload_method).
- `at_module_exit`: Run the dtor using the platform's
[`at_module_exit`][at_module_exit] (`__cxa_atexit` on all platforms
other than Windows, `atexit` on Windows).
- `at_binary_exit`: Run the dtor using the platform's
[`at_binary_exit`][at_binary_exit] (unsupported on Windows
platforms).
- `linker`: Register the dtor using the platform's
[link_section](#link_section) or
[export_name_prefix](#export_name_prefix) (unsupported on Apple
platforms).
[at_module_exit]: crate::native::at_module_exit
[at_binary_exit]: crate::native::at_binary_exit
</td></tr>
<tr><td><code>unsafe</code></td><td>
Marks a dtor as unsafe. Required.
The `dtor` crate rejects `#[dtor]` without marking the item unsafe;
that error can be suppressed by passing
`RUSTFLAGS="--cfg linktime_no_fail_on_missing_unsafe"` to Cargo.
</td></tr>
<tr><td><code>used(linker)</code></td><td>
Mark generated function pointers `used(linker)`. Requires nightly
for the nightly-only feature `feature(used_with_arg)` (see
<https://github.com/rust-lang/rust/issues/93798>).
This can be made the default by using the `cfg` flag
`linktime_used_linker` (`RUSTFLAGS="--cfg linktime_used_linker"`).
For a crate using this macro to function correctly with and without
this flag, it is recommended to add the following line to the top of
lib.rs in the crate root:
`#![cfg_attr(linktime_used_linker, feature(used_with_arg))]`
</td></tr>
</table>
# Defaults
## `ctor_export_name_prefix`
```rust
#[cfg(target_os = "aix")]
ctor_export_name_prefix = "__sinit80000000"
// default
ctor_export_name_prefix = ()
```
## `ctor_link_section`
```rust
#[cfg(target_vendor = "apple")]
ctor_link_section = "__DATA,__mod_init_func,mod_init_funcs"
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd",
target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly",
target_os = "illumos", target_os = "haiku", target_os = "vxworks", target_os =
"nto", target_family = "wasm"))]
ctor_link_section = ".init_array"
#[cfg(target_os = "none")]
ctor_link_section = ".init_array"
#[cfg(target_arch = "xtensa")]
ctor_link_section = ".ctors"
#[cfg(all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc")))]
ctor_link_section = ".CRT$XCU"
#[cfg(all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc"))))]
ctor_link_section = ".ctors"
#[cfg(all(target_os = "aix"))]
ctor_link_section = ()
// default
ctor_link_section = (compile_error! ("Unsupported target for #[ctor]"))
```
## `default_term_method`
```rust
#[cfg(target_vendor = "pc")]
default_term_method = at_module_exit
// default
default_term_method = at_binary_exit
```
## `default_unload_method`
```rust
// default
default_unload_method = at_module_exit
```
## `export_name_prefix`
```rust
#[cfg(target_os = "aix")]
export_name_prefix = "__sterm80000000"
// default
export_name_prefix = ()
```
## `link_section`
```rust
#[cfg(target_vendor = "apple")]
link_section = "__DATA,__mod_term_func,mod_term_funcs"
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd",
target_os = "netbsd", target_os = "openbsd", target_os = "dragonfly",
target_os = "illumos", target_os = "haiku", target_os = "vxworks", target_os =
"nto", target_family = "wasm"))]
link_section = ".fini_array"
#[cfg(target_os = "none")]
link_section = ".fini_array"
#[cfg(target_arch = "xtensa")]
link_section = ".dtors"
#[cfg(all(target_vendor = "pc", any(target_env = "gnu", target_env = "msvc")))]
link_section = ".CRT$XPU"
#[cfg(all(target_vendor = "pc", not(any(target_env = "gnu", target_env = "msvc"))))]
link_section = ".dtors"
#[cfg(all(target_os = "aix"))]
link_section = ()
// default
link_section = (compile_error! ("Unsupported target for #[dtor]"))
```
## `method`
```rust
#[cfg(target_vendor = "apple")]
method = at_module_exit
#[cfg(target_vendor = "pc")]
method = at_module_exit
#[cfg(target_family = "wasm")]
method = at_binary_exit
// default
method = linker
```
## `r#unsafe`
```rust
#[cfg(linktime_no_fail_on_missing_unsafe)]
r#unsafe = (no_fail_on_missing_unsafe)
// default
r#unsafe = ()
```
## `used_linker`
```rust
#[cfg(linktime_used_linker)]
used_linker = used_linker
// default
used_linker = ()
```