36个版本
0.2.8 | 2024年4月16日 |
---|---|
0.2.7 | 2024年2月26日 |
0.2.6 | 2023年12月12日 |
0.2.5 | 2023年9月26日 |
0.1.6 | 2018年12月30日 |
#22 in 过程宏
1,338,556 每月下载量
用于 1,411 个crates (310直接)
22KB
263 行
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将导致必然的panic。考虑在libc-print
crate中输出到stderr/stdout,特别是在#[ctor]
和#[dtor]
方法中。其他问题可能涉及早期代码中的信号处理或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]
#[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);
}
依赖项
~260–710KB
~17K SLoC