1 个不稳定版本
0.2.0 | 2023年5月15日 |
---|
#1534 in 过程宏
21KB
255 行
rust-ctor
Rust模块初始化/拆解函数(类似于C/C++中的__attribute__((constructor))
)用于Linux、OSX、FreeBSD、NetBSD、Illumos、OpenBSD、DragonFlyBSD、Android、iOS和Windows。
此库目前至少需要 Rust > 1.31.0 才能支持过程宏。
灵感来源于Neon项目中的此代码。
支持
此库在Linux、OSX和Windows上运行良好,并定期进行测试,支持+crt-static
和-crt-static
。其他平台受支持,但不是自动构建的一部分。此库在bin
和cdylib
输出中也能按预期工作,即:在程序或库启动/关闭时分别运行ctor
和dtor
。
警告
Rust的哲学是“主函数之前和之后不会发生任何事情”,而此库明确违反了这一点。在ctor
和dtor
函数中运行的代码应谨慎限制自己使用libc
函数和不受Rust stdlib服务依赖的代码。
例如,在dtor
函数中使用stdout将导致恐慌。考虑在#[ctor]
和#[dtor]
方法期间使用libc-print
crate进行输出到stderr/stdout。其他问题可能涉及早期代码中的信号处理或panic处理。
在大多数情况下,使用 sys_common::at_exit
比使用 #[dtor]
更合适。请注意风险!
在某些平台上,即使显式卸载,共享库的实际卸载可能要等到进程退出。这些规则很神秘,难以理解。例如,OSX 上的线程本地存储会影响这一点(参见 此评论)。
示例
将函数 foo
标记为模块构造函数,在静态库加载或可执行程序启动时调用
static INITED: AtomicBool = AtomicBool::new(false);
#[ctor]
fn foo() {
INITED.store(true, Ordering::SeqCst);
}
当静态库加载或可执行程序启动时创建一个填充了字符串的 HashMap
(新特性,版本 0.1.7
)
#[ctor]
/// This is an immutable static, evaluated at init time
static STATIC_CTOR: HashMap<u32, &'static str> = {
let mut m = HashMap::new();
m.insert(0, "foo");
m.insert(1, "bar");
m.insert(2, "baz");
m
};
在关闭时打印一条消息。注意,Rust 可能在此时刻关闭了一些 stdlib 服务。
#[dtor]
unsafe fn shutdown() {
// Using println or eprintln here will panic as Rust has shut down
libc::printf("Shutting down!\n\0".as_ptr() as *const i8);
}
内部原理
#[ctor]
宏利用链接器部分确保函数在启动时运行。
上述示例转换为以下 Rust 代码(大约)
#[used(linker)]
#[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".init_array")]
#[cfg_attr(target_os = "freebsd", link_section = ".init_array")]
#[cfg_attr(target_os = "netbsd", link_section = ".init_array")]
#[cfg_attr(target_os = "openbsd", link_section = ".init_array")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
static FOO: extern fn() = {
#[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")]
extern fn foo() { /* ... */ };
foo
};
#[dtor]
宏实际上创建了一个构造函数,该构造函数调用 libc::atexit
并传递提供的函数,即大致相当于
#[ctor]
fn dtor_atexit() {
libc::atexit(dtor);
}
依赖
~265–710KB
~17K SLoC