Module initialization/global constructor functions for Rust
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
ctor Update docs + bump to 0.1.4 Dec 6, 2018
tests Get dtor working on Windows Dec 6, 2018
.gitignore Initial version Dec 6, 2018
.travis.yml Remove allowed failures Dec 6, 2018
Cargo.lock Update docs + bump to 0.1.4 Dec 6, 2018
Cargo.toml Get dtor working on Windows Dec 6, 2018
README.md Update README with new dtor info Dec 6, 2018

README.md

rust-ctor

Build Status docs.rs crates.io

Module initialization functions for Rust (like __attribute__((constructor)) in C/C++) for Linux, OSX, and Windows.

This library currently requires Rust > 1.31.0 at a minimum for the procedural macro support.

Idea inspired by this code in the Neon project.

Warnings

Rust's philosophy is that nothing happens before or after main and this library explicitly subverts that. The code that runs in the ctor and dtor functions should be careful to limit itself to libc functions and code that does not rely on Rust's stdlib services.

For example, using stdout in a dtor function is a guaranteed panic.

In most cases, sys_common::at_exit is a better choice than #[dtor]. Caveat emptor!

Examples

Marks the function foo as a module constructor, called when a static library is loaded or an executable is started:

    static INITED: AtomicBool = ATOMIC_BOOL_INIT;

    #[ctor]
    fn foo() {
        INITED.store(true, Ordering::SeqCst);
    }

Print a message at shutdown time. Note that Rust may have shut down some stdlib services at this time.

    #[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);
    }

Under the Hood

The #[ctor] macro makes use of linker sections to ensure that a function is run at startup time.

The above example translates into the following Rust code (approximately):

    #[used]
    #[cfg_attr(target_os = "linux", link_section = ".ctors")]
    #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
    #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
    pub static foo: extern fn() = { 
        extern fn foo() { ... };
        foo 
    }

The #[dtor] macro effectively creates a constructor that calls libc::atexit with the provided function, ie roughly equivalent to:

    #[ctor]
    fn dtor_atexit() {
        libc::atexit(dtor);
    }