Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I expose a compile time generated static C string through FFI?

Tags:

rust

ffi

I am trying to embed a version number into a library. Ideally, this should be a static C string that can be read and doesn't need any additional allocation for reading the version number.

On the Rust side, I am using vergen to generate the versioning information like this:

pub static VERSION: &str = env!("VERGEN_SEMVER");

and I would like to end up with something like

#[no_mangle]
pub static VERSION_C: *const u8 = ... ;

There seems to be a way to achieve this using string literals, but I haven't found a way to do this with compile time strings. Creating a new CString seems to be beyond the current capabilities of static variables and tends to end with an error E0015.

A function returning the pointer like this would be acceptable, as long as it does not allocate new memory.

#[no_mangle]
pub extern "C" fn get_version() -> *const u8 {
    // ...
}

The final type of the variable (or return type of the function) doesn't have to be based on u8, but should be translatable through cbindgen. If some other FFI type is more appropriate, using that is perfectly fine.

like image 762
Michael Mauderer Avatar asked Jan 01 '23 13:01

Michael Mauderer


1 Answers

By ensuring that the static string slice is compatible with a C-style string (as in, it ends with the null terminator byte \0), we can safely fetch a pointer to the beginning of the slice and pass that across the boundary.

pub static VERSION: &str = concat!(env!("VERGEN_SEMVER"), "\0");

#[no_mangle]
pub extern "C" fn get_version() -> *const c_char {
    VER.as_ptr() as *const c_char
}

Here's an example in the Playground, where I used the package's version as the environment variable to fetch and called the function in Rust.

like image 141
E_net4 stands with Ukraine Avatar answered Jan 05 '23 16:01

E_net4 stands with Ukraine