#constructor #attributes #function #openbsd #freebsd #static #linux

ctor-used-linker

__attribute__((constructor)) for Rust

1 个不稳定版本

0.2.0 2023年5月15日

#1534 in 过程宏

Apache-2.0 OR MIT

21KB
255

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将导致恐慌。考虑在#[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