sonos / ffi-convert-rs

Easier and safer interface between Rust, C, and other languages
https://docs.rs/ffi-convert/
Other
106 stars 22 forks source link

cbindgen not creating the right headers for ffi-convert-rs structs #52

Closed Masber closed 5 months ago

Masber commented 5 months ago

Dear ffi convert team,

I am learning go, rust and the interactions between these 2 languages by consuming rust methods by golang.

I have done some tests and I am getting error in cgo trying to understand the header files generated by dbindgen...

This is my rust code

use ffi_convert::RawBorrow;
use ffi_convert::{AsRust, CArray, CDrop, CReprOf, CStringArray, RawPointerConverter};
use futures::executor::block_on;
use mesa::hsm::group::r#struct::{HsmGroup, Member};
use std::ffi::{c_char, c_float, c_int, c_schar, c_uchar, c_uint, CStr};

#[derive(CReprOf, AsRust, CDrop, RawPointerConverter, Debug)]
#[target_type(Member)]
pub struct CMember {
    #[nullable]
    ids: *const CStringArray,
}

#[repr(C)]
#[derive(CReprOf, AsRust, CDrop, RawPointerConverter, Debug)]
#[target_type(HsmGroup)]
pub struct CHsmGroup {
    label: *const libc::c_char,
    #[nullable]
    description: *const libc::c_char,
    #[nullable]
    members: *const CMember,
    #[nullable]
    exclusive_group: *const libc::c_char,
    #[nullable]
    tags: *const CStringArray,
}

#[no_mangle]
pub extern "C" fn get_hsm_group(
    data: CHsmGroup,
) {
 // do something
}

This is my build.rd for dbindgen

extern crate cbindgen;

use std::env;

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

    cbindgen::Builder::new()
        .with_crate(crate_dir)
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file("bindings.h");
}

And this is the headers file generated

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct CMember CMember;

typedef struct CHsmGroup {
  const char *label;
  const char *description;
  const struct CMember *members;
  const char *exclusive_group;
  const CStringArray *tags;
} CHsmGroup;

void get_hsm_group(struct CHsmGroup data);

I know very little but I think the below may not right?

typedef struct CMember CMember;

I would expect something like below?

typedef struct CMember {
  const char *const *ids;
} CMember;

typedef struct CHsmGroup {
  const char *label;
  const char *description;
  const struct CMember *members;
  const char *exclusive_group;
  const char *const *tags;
} CHsmGroup;

I crated an example here https://github.com/Masber/rust-ffi this creates a shared library that I am using in a Go code, the header file is automatically generated by cbindgen during the build process cargo build --release

fredszaq commented 5 months ago

Hi @Masber.

you're missing a #[repr(C)] annotation on the CMember struct. cbindgen will declare this struct as opaque in that case (ie the struct exists and you can have pointers to it but you can't access fields as the memory layout is not guaranteed and the rust compiler may have done some funky things with it)

closing this as this is definitely not an ffi-convert issue