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 过程宏

Download history 240781/week @ 2024-04-28 251816/week @ 2024-05-05 255261/week @ 2024-05-12 253976/week @ 2024-05-19 262472/week @ 2024-05-26 331730/week @ 2024-06-02 309836/week @ 2024-06-09 340079/week @ 2024-06-16 356665/week @ 2024-06-23 337066/week @ 2024-06-30 347168/week @ 2024-07-07 338155/week @ 2024-07-14 336004/week @ 2024-07-21 335287/week @ 2024-07-28 335704/week @ 2024-08-04 309922/week @ 2024-08-11

1,338,556 每月下载量
用于 1,411 个crates (310直接)

Apache-2.0 OR MIT

22KB
263

rust-ctor

Build Status docs.rs crates.io

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。其他平台也得到支持,但不是作为自动构建的一部分进行测试。此库在bincdylib输出中也能按预期工作,即:在可执行文件或库启动/关闭时分别运行ctordtor

警告

Rust的哲学是,主函数之前和之后不会发生任何事情,而这个库明确地违反了这一点。在ctordtor函数中运行的代码应谨慎地仅限于使用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