#[ctor]Expand description
Marks a function or static variable as a library/executable constructor. This uses OS-specific linker sections to call a specific function at load time.
§Important notes
Rust does not make any guarantees about stdlib support for life-before or
life-after main. This means that the ctor crate may not work as expected
in some cases, such as when used in an async runtime or making use of
stdlib services.
Multiple startup functions/statics are supported, but the invocation order is not guaranteed.
The ctor crate assumes it is available as a direct dependency, If you
re-export ctor items as part of your crate, you can use the crate_path
parameter to redirect the macro’s output to the correct crate, or use the
declarative::ctor form.
§Examples
Print a startup message (using libc_print for safety):
use libc_print::std_name::println;
#[ctor(unsafe)]
fn foo() {
// Using libc_print which is safe in `#[ctor]`
println!("Hello, world!");
}
println!("main()");Make changes to static variables:
use ctor::*;
use std::sync::atomic::{AtomicBool, Ordering};
static INITED: AtomicBool = AtomicBool::new(false);
#[ctor(unsafe)]
fn set_inited() {
INITED.store(true, Ordering::SeqCst);
}Initialize a HashMap at startup time:
#[ctor(unsafe)]
pub static STATIC_CTOR: HashMap<u32, String> = {
let mut m = HashMap::new();
for i in 0..100 {
m.insert(i, format!("x*100={}", i*100));
}
m
};§Details
The #[ctor] macro makes use of linker sections to ensure that a function
is run at startup time.
#[ctor(unsafe)]
fn my_init_fn() {
/* ... */
}The above example translates into the following Rust code (approximately):
#[used]
#[cfg_attr(target_os = "linux", link_section = ".init_array")]
#[cfg_attr(target_vendor = "apple", link_section = "__DATA,__mod_init_func,mod_init_funcs")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
/* ... other platforms elided ... */
static INIT_FN: extern fn() = {
extern fn init_fn() { my_init_fn(); };
init_fn
};For static items, the macro generates a std::sync::OnceLock that is
initialized at startup time. #[ctor] on static items requires the
default std feature.
#[ctor]
static FOO: HashMap<u32, String> = unsafe {
let mut m = HashMap::new();
for i in 0..100 {
m.insert(i, format!("x*100={}", i*100));
}
m
};The above example translates into the following Rust code (approximately),
which eagerly initializes the HashMap inside a OnceLock at startup time:
static FOO: FooStatic = FooStatic { value: ::std::sync::OnceLock::new() };
struct FooStatic {
value: ::std::sync::OnceLock<HashMap<u32, String>>,
}
impl ::core::ops::Deref for FooStatic {
type Target = HashMap<u32, String>;
fn deref(&self) -> &Self::Target {
self.value.get_or_init(|| unsafe {
let mut m = HashMap::new();
for i in 0..100 {
m.insert(i, format!("x*100={}", i*100));
}
m
})
}
}
#[ctor]
unsafe fn init_foo_ctor() {
_ = &*FOO;
}