简体   繁体   中英

Rust ffi include dynamic library in cross platform fashion

I would like to include a dynamic C library in Rust with FFI.

The library is actually also build with Rust, but exposes a C interface, so that it can be used from other languages, too. When I build the library (type: cdylib ) with cargo I get a .dylib on MacOS and a .dll as well as a .dll.lib file on windows. These libraries also get different names, derived from the project name ( libmy_lib.dylib on MacOS and my_lib.dll as well as my_lib.dll.lib on Windows).

I would like to reference these files in a cross-platform way. Because currently I have to use

#[link(name = "my_lib.dll", kind = "dylib")]

on windows, whereas on MacOS I need to use

#[link(name = "my_lib", kind = "dylib")]

I have already tried to rename the my_lib.dll.lib to my_lib.lib , but I still get a Linker Error, saying

LINK: fatal error LNK1181: cannot open input file 'my_lib.lib'

How can I reference the files, so that I can use my code for Mac and Windows? If thats only possible with cfg_attr tags I would also accept that. Ideally I would also like to get rid of the .lib file for windows if possible.

You could use crate libloading

Example:

let lib = unsafe {
    #[cfg(unix)]
    let path = "mylib.so";
    #[cfg(windows)]
    let path = "mylib.dll";
    libloading::Library::new(path).expect("Failed to load library")
};
let func: libloading::Symbol<unsafe extern fn() -> u32> = unsafe {
     lib.get(b"my_func").expect("Failed to load function `my_func`")
};
// Can call func later while `lib` in scope

For what it's worth, I found a temporary solution for this now.

I used this pattern:

#[cfg(windows)]
#[link(name = "my_lib.dll", kind = "dylib")]
extern {
    // Reference the exported functions
}

#[cfg(unix)]
#[link(name = "my_lib", kind = "dylib")]
extern {
    // Reference the exported functions
}

I don't like it that much, because I had to define the very same extern{} block twice, but it works and I could also extend this pattern to for example use #[cfg(target_os = "macos")] if needed...

EDIT: Thanks to @Angelicos Phosphoros I improved the code a bit by using a macro like so:

/// Import native functions with the Rust FFI
macro_rules! import_native_functions {
    () => {
        // Reference the exported functions
    };
}

#[cfg(windows)]
#[link(name = "my_lib.dll", kind = "dylib")]
extern {
    import_native_functions!();
}


#[cfg(unix)]
#[link(name = "my_lib", kind = "dylib")]
extern {
    import_native_functions!();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM