rustdllshared-libraries

How to dynamically call a function in a shared library?


I have a Rust project, set as an executable. I am trying to call an external shared library, also written in Rust, dynamically. I have the external library compiled on release, and I have tried both crate types cdylib and dylib.

I am using the crate libloading, which claims to be able to dynamically load shared library functions, as long as they only use primitive arguments. I keep getting this error when I try to run my code using this crate.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: GetProcAddress { source: Os { code: 127, kind: Other, message: "The specified procedure could not be found." } }', src\main.rs:14:68
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

main.rs/main():

    let now = Instant::now();

    unsafe {
        let lib = libloading::Library::new(
            "externtest.dll").unwrap();
        let foo3: Symbol<extern fn(i32) -> i32> = lib.get(b"foo").unwrap();

        println!("{}", foo(1));
    }

    let elapsed = now.elapsed();
    println!("Elapsed: {:?}", elapsed);

lib.rs:

pub extern "C" fn foo3(i:i32) -> i32{
    i
}

Solution

  • First, your library function is called "foo3", but you're trying to load the symbol "foo".

    Second, the library function's symbol may not match it's name due to mangling. You need to tell the compiler not to do that with the #[no_mangle] attribute:

    #[no_mangle]
    pub extern "C" fn foo(i: i32) -> i32 {
        i
    }
    

    Third, this is mostly a stylistic choice, but I'd specify the ABI extern "C" when defining your symbol. Even though extern with no epecified ABI uses the "C" ABI, I've found it better to be explicit.

    use libloading::{Library, Symbol};
    
    fn main() {
        unsafe {
            let lib = Library::new("externtest.dll").unwrap();
            let foo = lib
                .get::<Symbol<extern "C" fn(i32) -> i32>>(b"foo")
                .unwrap();
    
            println!("{}", foo(1));
        }
    }
    

    The above should work without issue.