mozilla / cbindgen

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

Suitability for opaque-types(-only) FFI types #492

Open chrysn opened 4 years ago

chrysn commented 4 years ago

A library I'm currently binding to Rust (liboscore) has something of a compile-time module system (think back-end, not plug-in; there's only one back-end at a compile time) that works like this:

Is this a use case cbindgen aims to support?

If so, there's a few things I'd need and could attempt to work on (but first is the question of whether this is desirable in the first place):

edit: added reference to export_name item

emilio commented 4 years ago

This seems generally reasonable though I'm not sure I've grasped all the details of what you want.

Declaring types as opaque should "just work" if you don't make them repr(C) or such.

The function signatures are exported in parallel to the types. That doesn't hurt and even helps the C compiler verify that everyone agrees on signatures, but they need to be exact; a size_t_is_usize workaround like in rust-lang/rust-bindgen#1671 could help there (but probably just the code that mixes them should be fixed).

Can you clarify? What functions are not getting exported right now (but should)?

Something similar to #[link(name=...)] (edit: or #[export_name=...]?) for these types would be convenient, as it would allow the use of rustish type names throughout the code, which only get named mylibrary_mymodule_typename (from TypeName in Rust which has modules/namespaces) at export time.

We have export.rename which I think would do what you want, right? Something like this.

We could somehow move it to the type declaration instead of the config maybe.

chrysn commented 4 years ago

Declaring types as opaque should "just work" if you don't make them repr(C) or such.

The issue I'm having with them is that while I don't need access from C to their internals, I need them to be complete. They're used by the C library like this:

backendtype_t state;
backend_initialize(&state);
backend_work_on(&state, ...);

Making that backendtype_t repr(C) is not really feasible because it may contain all kinds of ZSTs and what so not you'd use when you don't expect to have to use a C API.

Can you clarify? What functions are not getting exported right now (but should)?

The other way 'round: the function signatures are exported, that's something I originally disliked (after all, the canonical signature is in the specified interface that comes from the C library) but now came to appreciate as the duplicate signatures don't hurt but provide additional verification.

But then, those types need to match precisely, this means

We have export.rename which I think would do what you want, right?

That helps indeed, thanks, I missed it, that works for me now.

As you hinted, I'd prefer to have some declaration inline instead of cbindgen.toml lists, but anyway.

There's already the type my_c_style_type = RustType; way of specifying things, but that requires me to use a prefix to get all the Rust definitions out of the main C namespace, but then the my_c_style_type gets prefixed as well, and unlike function names I can't #[no_mangle] them to avoid the prefixing. may even type oscore_x = X as long as X can be prefixed but well

emilio commented 4 years ago

The issue I'm having with them is that while I don't need access from C to their internals, I need them to be complete. [...] Making that backendtype_t repr(C) is not really feasible because it may contain all kinds of ZSTs and what so not you'd use when you don't expect to have to use a C API.

Ah, that seems pretty hard to do. Cbindgen doesn't have access to rustc's internals so it can't know the type layout to generate something useful. Plus even if we had it, whatever it generates would be dependent on the rust version that was used at the time, because Rustc could change the layout to its will.

The other way 'round: the function signatures are exported, that's something I originally disliked (after all, the canonical signature is in the specified interface that comes from the C library) but now came to appreciate as the duplicate signatures don't hurt but provide additional verification.

Ah I see... Yeah I find it useful to catch mistakes, fwiw.

Implementations like pub extern "C" fn initialize(state: &mut MaybeUninit) { ... } need something like #406 if that even suffices, or workarounds (which would probably mean just making the function initialize(state: *mut State)).

Yeah, I think #406 is the right way to address this.

aidanhs commented 1 year ago

Just for cross referencing purposes since I've been skimming through related issues, https://github.com/mozilla/cbindgen/issues/24 relates to the desire to have a way to automatically generate things like:

currently, as a workaround, I have things like typedef struct {uint64_t dontuse[16];} oscore_crypto_aead_encryptstate_t; in there