A previous post was about getting a simple rust dynamic library working. The next thing I wanted to do was try passing a more complex type from the dynamic library to the executable using it.

First, I changed dynamiclib to:


#[derive(Debug)]
pub struct Tuple (u32,);

#[derive(Debug)]
pub struct MyStruct {
s1: &'static str,
s2: String,
t: Tuple,
}

#[no_mangle]
pub extern "C" fn test() -> MyStruct {
MyStruct {
s1: "hello",
s2: "world".to_string(),
t: Tuple(47),
}
}
And dynamic to:

#[link(name="dynamiclib")]
extern {
fn test() -> MyStruct;
}

fn main() {
let retval = unsafe { test() };
println!("Got: {:?}", retval);
}
And (somewhat surprisingly) it worked as expected. Although you get the following error:

warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type, #[warn(improper_ctypes)] on by default
At first I considered appeasing the warning, but if it's a library written in rust and called from rust, shouldn't the default
repr(Rust)
be safe/correct?

Next, I decided to try loading and re-loading the shared library using this more complex struct... and I started getting SIGSEGV the second time I attempted to use the library.

I came across libloading (crates.io) which purports to be safer wrapper for working with dyanmic libraries, and if nothing else has much better documentation.

A quick change to dynamic/src/main.rs (devoid of error-checking):


let lib = Library::new("libdynamiclib.dylib").unwrap();
let test: Symbol MyStruct> = unsafe {
lib.get(b"test\0").unwrap()
};
println!("Got: {:?}", test());
And it works correctly even when re-loading the library. So, I was either using stale symbols, or something else. Still several things that I obviously don't fully understand. Hopefully pouring over Rustonomicon will reveal the secrets to me.