-
Notifications
You must be signed in to change notification settings - Fork 771
Description
Problem
The goal is to have c headers be the source of truth and then have bindgen generate function signatures that can be implemented by rust code.
the following code is generated by this header
/**
* @brief Set the last error message
* @param message Error message
*/
void error_set_last_message(const char* message);
/**
* @brief Get the last error message
* @return Last error message or NULL if no error occurred
*/
const char* error_last_message();unsafe extern "C" {
#[doc = " @brief Set the last error message\n @param message Error message"]
pub fn error_set_last_message(message: *const ::std::os::raw::c_char);
}
unsafe extern "C" {
#[doc = " @brief Get the last error message\n @return Last error message or NULL if no error occurred"]
pub fn error_last_message() -> *const ::std::os::raw::c_char;
}I would like bindgen to generate something like the following
pub trait error_api {
#[doc = " @brief Set the last error message\n @param message Error message"]
unsafe extern "C" fn error_set_last_message(message: *const ::std::os::raw::c_char);
#[doc = " @brief Get the last error message\n @return Last error message or NULL if no error occurred"]
unsafe extern "C" fn error_last_message() -> *const ::std::os::raw::c_char;
}With some sort of builder setting like
let bindings = bindgen::builder()
.function_impl_trait("error_.*", "error_api");Then using this would be like
pub struct Extern;
impl error_api for Extern {
#[unsafe(no_mangle)]
unsafe extern "C" fn error_set_last_message(message: *const ::std::os::raw::c_char) {
...
}
#[unsafe(no_mangle)]
unsafe extern "C" fn error_last_message() -> *const ::std::os::raw::c_char {
...
}
}Motivation
A lot of code today is written in c++ / c with a public c-api that is exported so that other languages / customers can interact with the underlying code without having its source. In an effort to move more code over to rust having some way of using the c headers as a source of truth would make it easier to incrementally port legacy code bases over to rust.
Alternative solutions
-
Using a tool like cbindgen to generate the header files from the rust code. While this solution is good i would still prefer to have the headers be the source of truth for the definitions of the functions.
-
Bindgen can be extended to generate something like the following instead of the extern "C" blocks.
#[doc = " @brief Set the last error message\n @param message Error message"]
#[repr(transparent)]
pub struct error_set_last_message(pub unsafe extern "C" fn(message: *const ::std::os::raw::c_char));
#[doc = " @brief Get the last error message\n @return Last error message or NULL if no error occurred"]
#[repr(transparent)]
pub struct error_last_message(pub unsafe extern "C" fn() -> *const ::std::os::raw::c_char);And then its up to the library author to implement and expose these functions and can use these types to validate they are the same as the header. Also has the advantage of allowing bindgen to be used with dlopen
Related rust-lang/rust#58493