mozilla / cbindgen

A project for generating C bindings from Rust code
Mozilla Public License 2.0
2.43k stars 315 forks source link

Opaque Pointer #835

Closed coffeebe4code closed 1 year ago

coffeebe4code commented 1 year ago

I am attempting to turn a non c api compatible pointer back to the caller.

I just want to treat it as an opaque pointer. I'm not interested in converting all the fields and making a repr(C) compatible struct.

Here is an example.

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CL_FunctionBuilder_finalize(builder: *mut FunctionBuilder) -> () {
    let ubuilder = unsafe {
        assert!(!builder.is_null());
        core::ptr::read(builder)
    };
    ubuilder.finalize();
}

Is there any way to tell cbindgen to honor this?

emilio commented 1 year ago

The issue is that cbindgen can't find the FunctionBuilder at all, but it does the right thing if you define it:

struct FunctionBuilder {}

#[no_mangle]
pub extern "C" fn CL_FunctionBuilder_finalize(builder: *mut FunctionBuilder) -> () {
    let ubuilder = unsafe {
        assert!(!builder.is_null());
        core::ptr::read(builder)
    };
    ubuilder.finalize();
}

So this works, it's just a matter of the specific thing you're doing. If FunctionBuilder is on a different crate you probably need to let cbindgen run on that crate too?

coffeebe4code commented 1 year ago

@emilio

If FunctionBuilder is on a different crate you probably need to let cbindgen run on that crate too?

I'm not sure what you mean. FunctionBuilder is defined in another crate. craneliftto be precise. It has no C compatible API's. I am trying to expose a C compatible api. However, I don't want to figure out how to make every struct and every property c compatible, and then do a translation from a #[repr(C)] struct to #[repr(Rust)]. I want FunctionBuilder to be treated as essentially a typedef to a void pointer, and let rust deal with everything on that object.

I know I can make a struct transparent like so.

#[repr(transparent)]
pub struct CVariable(u32);

And this translation is incredibly easy. I'm just hoping there is something similar for an opaque pointer.

I'm just hoping there is a way to do what I am looking for. Please let me know if there is anything close. This is my first time using cbindgen, and the docs didn't quite cover something like this.

coffeebe4code commented 1 year ago

Let me know if there is a better way, but I did this to "resolve" my issue. I have yet to get the tool to fully work based on a different issue I have open. But this should theoretically work.

I created a craneliftc_extra.h file, and put my typedefs in there, and then specified the include in cbindgen.toml for those extras.

cbindgen.toml

includes = ["craneliftc_extra.h"]

craneliftc_extra.h

typedef void *FunctionBuilder;
typedef void *UserFuncName;
typedef void *Flags;
typedef void *AbiParam;
typedef void *Builder;
typedef void *Signature;
typedef void *FunctionBuilderContext;
typedef void *Function;
emilio commented 1 year ago

@emilio

If FunctionBuilder is on a different crate you probably need to let cbindgen run on that crate too?

I'm not sure what you mean. FunctionBuilder is defined in another crate. craneliftto be precise. It has no C compatible API's. I am trying to expose a C compatible api. However, I don't want to figure out how to make every struct and every property c compatible, and then do a translation from a #[repr(C)] struct to #[repr(Rust)]. I want FunctionBuilder to be treated as essentially a typedef to a void pointer, and let rust deal with everything on that object.

Right, I think you can do something like this to make sure cbindgen visits the cranelift crate, even tho there's no FFI-compatible thing there.

You probably want struct FunctionBuilder; etc rather than typedef void* FunctionBuilder; in any case, so that a pointer to FunctionBuilder cannot be dereferenced.