dtor 1.0.6

Global, no_std-compatible destructors for all platforms that run after main (like C/C++ __attribute__((destructor)))
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
The crate is part of the [`linktime`](https://crates.io/crates/linktime) project.

[![GitHub](https://img.shields.io/badge/repo-github-blue)](https://github.com/mmastrac/linktime) [![Crates.io License](https://img.shields.io/crates/l/link-section)](https://crates.io/crates/link-section) [![Build Status](https://github.com/mmastrac/linktime/actions/workflows/rust.yml/badge.svg)](https://github.com/mmastrac/linktime/actions/workflows/rust.yml) 


| crate | |
| --- | --- |
| `linktime`<br>[![docs.rs]https://docs.rs/linktime/badge.svg]https://docs.rs/linktime [![crates.io]https://img.shields.io/crates/v/linktime.svg]https://crates.io/crates/linktime | Convenience crate for `ctor`, `dtor` and `link-section` |
| `ctor`<br>[![docs.rs]https://docs.rs/ctor/badge.svg]https://docs.rs/ctor [![crates.io]https://img.shields.io/crates/v/ctor.svg]https://crates.io/crates/ctor | Module initialization functions before main |
| `dtor`<br>[![docs.rs]https://docs.rs/dtor/badge.svg]https://docs.rs/dtor [![crates.io]https://img.shields.io/crates/v/dtor.svg]https://crates.io/crates/dtor | Module shutdown functions before main |
| `link-section`<br>[![docs.rs]https://docs.rs/link-section/badge.svg]https://docs.rs/link-section [![crates.io]https://img.shields.io/crates/v/link-section.svg]https://crates.io/crates/link-section | Linker-managed typed (slices) and untyped sections |
| `scattered-collect`<br>[![docs.rs]https://docs.rs/scattered-collect/badge.svg]https://docs.rs/scattered-collect [![crates.io]https://img.shields.io/crates/v/scattered-collect.svg]https://crates.io/crates/scattered-collect | Linker-managed collections: slices, sorted slices, maps |
# 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

| Platform                   | Link Section                              | at_binary_exit | at_module_exit       |
| -------------------------- | ----------------------------------------- | -------------- | -------------------- |
| 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);
}
```
# Re-exporting from another crate

The macros assume this crate is available as a direct dependency, resolving their
support paths through the crate's own name. If you re-export this crate's items as
part of your own crate (so that downstream users don't need to depend on it
directly), you have two options:

- (preferred) use the declarative macro form. It resolves its support paths
  relative to your re-export, so no extra configuration is required.
- Alternatively, pass the `crate_path` attribute to redirect the macro's
  generated output to the path where this crate has been re-exported.

See the `crate_path` entry in the *Macro Attributes* section below for the exact
syntax for this crate.
# Crate Features

| Cargo feature | Description |
| --- | --- |
| `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>

 The path to the `dtor` crate containing the support macros. If you
 re-export `dtor` items as part of your crate, you can use this to
 redirect the macro's output to the correct crate.

 Using the declarative [`dtor!`][d] form is
 preferred over this parameter.

 [d]: crate::declarative::dtor!


</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_os = "windows", any(target_env = "gnu", target_env = "msvc")))]
ctor_link_section = ".CRT$XCU"

#[cfg(all(target_os = "windows", not(any(target_env = "gnu", target_env = "msvc"))))]
ctor_link_section = ".ctors"

#[cfg(target_os = "uefi")]
ctor_link_section = ".init_array"

#[cfg(target_os = "aix")]
ctor_link_section = ()

 // default
ctor_link_section = ".init_array"
 ```

## `default_term_method`

 ```rust
#[cfg(target_os = "windows")]
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 = "dragonfly", target_os = "illumos",
target_os = "haiku", target_os = "vxworks", target_os = "nto", target_family =
"wasm"))]
link_section = ".fini_array"

#[cfg(target_os = "openbsd")]
link_section = ".dtors"

#[cfg(target_os = "none")]
link_section = ".fini_array"

#[cfg(target_arch = "xtensa")]
link_section = ".dtors"

#[cfg(all(target_os = "windows", any(target_env = "gnu", target_env = "msvc")))]
link_section = ".CRT$XPU"

#[cfg(all(target_os = "windows", not(any(target_env = "gnu", target_env = "msvc"))))]
link_section = ".dtors"

#[cfg(target_os = "uefi")]
link_section = ".fini_array"

#[cfg(target_os = "aix")]
link_section = ()

 // default
link_section = ".fini_array"
 ```

## `method`

 ```rust
#[cfg(target_vendor = "apple")]
method = at_module_exit

#[cfg(target_os = "windows")]
method = at_module_exit

#[cfg(target_family = "wasm")]
method = at_binary_exit

#[cfg(target_os = "openbsd")]
method = at_module_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 = ()
 ```