Defining structs / enums based on .h file input

Emptying out text, as I'd like to wipe these, please.

3 Likes

Yes, that's what bindgen is meant to do. If I remember correctly, it should work for any system where it has access to clang. You should also be able to generate once and use from then on, barring platform-specific codegen.

It will export all definitions in the header, which includes enums, structs, and functions.

This crate is to generate Rust code which will be able to call into C programs, but you're not forced to use it this way. The only thing which is possibly unnecessary in this case is that every struct will be repr[C].

That's the primary use case, but it can be used for the other way around.

If the majority of your header files are functions that need to be implemented by Rust code, though, you're right that bindgen isn't exactly right. It can be made right, but you'd need to do more work.

Specifically, bindgen produces functions like:

extern "C" {
    pub fn func_name(pupper: *mut u32);
}

You would need to manually remove the extern block, and add function implementations:

pub fn func_name(pupper: *mut u32) {
    // (whatever actually implements this)
}

It's not hard work, but it is manual.


The other tool, cbindgen, is the current state-of-the-art package from writing Rust libraries with C interfaces.

It doesn't read .h files, but it will produce one from your Rust code. I think the assumption is that if you're primarily implementing Rust functions, then having a tool which goes from a .h header into a bunch of empty function declarations would be much less useful than a tool which reads .rs files and generates the corresponding .h.


That actually brings up a question. If you have a .h file, what exact rust code would you want auto-generated, and how should it output functions?

Most code generation tools are rerun periodically, every time the source is updated. The first run could just generate a .rs file with empty function implementations. But then I assume you'd want to implement those functions - to write code inside them.

I think dealing with functions on the second run would be a hard problem, and that might be why this tool doesn't exist. Ideally, you'd want it to be automatic - so it could "just work" on an existing .rs file. But then it'd have to A) read the rust file, B) identify all the functions whose declarations, but not bodies, need to be replaced with those from the .h file, and C) make those replacements, while still keeping variable names and bodies from the old code.

The fact that we need to edit the generated .rs file after it's generated makes this job a lot harder to get right, and I think that's why people choose to use the other option - generating a .h from the .rs.

Maybe, but if you're just doing it once, it's probably easier to just search and replace them away.

I couldn't find any options in bindgen for controlling visibility of the fields. They might add it though, if one of us makes a bug report?

Besides that, this isn't a good solution, but you could always do a search-and-replace on the output, and put it in a script for automation - something like:

#!/bin/sh
bindgen foo.h > src/gen/foo.rs
# only replace pub with indentation, so as only to replace field publicity
sed -i 's/^    pub /    pub(crate) /' src/gen/foo.rs

It's hacky, but it should work, and the only manual work it needs is checking the git diff after each run to ensure that the replacement hasn't messed up.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.