-
Notifications
You must be signed in to change notification settings - Fork 687
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate C code to export static inline functions #1090
Comments
For now, you can also compile it with |
Won't that prevent inlining inside xed? |
Further, -fno-inline-functions and .generate_inline_functions(true) doesn't actually seem to generate bindings for those functions. Perhaps because they are static inline? |
Yup, I think so, which is unfortunate, I agree.
Yeah, if they aren't visible in other translation units we can't generate symbols for them... I guess wrapping them is the best solution then |
What's the best approach to implement this? |
It looks like currently static inline functions end up in the ir with a name of None. |
This feature is something I've wanted for a while, but haven't had the need to actually implement. The biggest open questions I have are:
A new pass over the final IR, probably called from inside It would be awesome if there was a
Unfortunately, I don't have any insight into why this might be off the top of my head. |
This is fixed with #1091 I'm probably not going to look at this again anytime soon as I've switched from using https://github.com/valarauca/xed-sys/ to https://github.com/zyantific/zydis-rs which doesn't have this problem. |
|
We have this trouble on YJIT quite extensively - commenting and subscribing here :-) |
With the recent advancements in C2Rust, the #1344 route for this
is becoming more viable again. (Or maybe even going all C2Rust -- in a
sense, bindgen is "just" what C2Rust should be when let lose on a `.h`
files, albeit with many more bells and whistles).
|
Just using C2Rust might not work well for us - one thing we need is more support for complex preprocessor defines than bindgen gives (e.g. operators on constants in a define.) In general, we use a lot of C preprocessor constants. Could work well for somebody else, though! Some method of integrating the two tools could be interesting. But it also sounds like it doesn't really exist yet. So we'd need to do a significant amount of tools work on our large existing codebase to make it happen. Not impossible, but not on our short-term roadmap, I don't think. |
I was thinking about tackling this issue. However, I'd like to understand a bit better what needs to be done first. Let's say we have a header file static inline int foo(); In my head what would happen is that we would generate an intermediate #include <header.h>
int foo_wo_inline() {
return foo();
} and then this file would be processed by bindgen and produce something like this: extern "C" {
fn foo_no_inline() -> ::std::os::raw::c_int;
}
pub unsafe extern "C" fn foo() -> ::std::os::raw::c_int {
foo_no_inline()
} Despite of the name juggling, is this a good way to approach this issue? |
@pvdrz That sounds basically like what we are currently doing manually in our project. Some comments:
On the Rust side I think using
|
I started taking a deeper look at this today and I have a couple questions (@emilio, @fitzgen):
Update: I have a very incomplete but working code generator for C and is good enough to emit the wrapper functions we need. The only thing I need to move forward is knowing how to handle these "two stages" where we first find all the static inline functions and then run bindgen again over the generated files. |
I've done some progress this week. Right now when a header file has inline functions like this one: typedef int num;
static inline num foo(num arg) { return arg + 42; }
inline num bar(num arg) { return arg + 0x45; }
num baz(num arg); the following is printed to stdout: [bindgen-tutorial 0.1.0] cargo:rerun-if-changed=new_wrapper.h
[bindgen-tutorial 0.1.0] FOUND INLINED FUNCTION: foo
[bindgen-tutorial 0.1.0] FOUND INLINED FUNCTION: bar
[bindgen-tutorial 0.1.0] HEADERS
[bindgen-tutorial 0.1.0] headers: int foo__extern(int arg);
[bindgen-tutorial 0.1.0] headers: int bar__extern(int arg);
[bindgen-tutorial 0.1.0] WRAPPERS
[bindgen-tutorial 0.1.0] wrappers: int foo__extern(int arg) { return foo(arg); }
[bindgen-tutorial 0.1.0] wrappers: int bar__extern(int arg) { return bar(arg); } |
@emilio I have a question before going any further on this issue. It seems the most robust way of generating the necessary rust code for inlined functions is using bindgen to process the generated c code that wraps the inlined functions. Regardless of how this c code was generated. We would need to compile the c code first and then "re-run" bindgen over it respecting all the The only way to do this that I can think of is making So the question is: Would it make sense to split |
Regardless of how this c code was generated. We would need to compile
the c code first and then "re-run" bindgen over it respecting all the
`BindgenOptions` that were set by the user.
I'd be careful about compiling code ourselves (because the CFLAGs we see
might not be fully accurate for compilation, eg. because C code is
compiled by GCC, and the options were stripped down to support LLVM). At
least in my use case (riot-sys), it would be prefereable to have the C
file exported somewhere where the remaining build system could pick it
up and build it together with the rest of the C code.
|
I think that one way to solve this would be to add some sort of callback so the user can specify "how" to compile this generated c code and then bindgen do the final step of generating the bindings including the generated header file. Does that sound like a good solution? |
Why does the C-code need to be compiled before bindgen can be run? Why can't bindgen just generate the new header files first, and then generate the bindings? I'm a bit confused why compilation suddenly is necessary. |
Yeah you're right. I thought that compiling before would serve as a "sanity check" for the generated code but in principle bindgen should be able to generate bindings for the new header files without compiling the new source code beforehand. |
Ok I have a very hacky PoC here. The pipeline is be the following:
From here the user can compile the generated source files into a library and use the I think this is a good approach as it can be done incrementally without a huge PR:
There are alternatives here like:
I'd love to have some input before committing to any path in particular :) |
This adds a mechanism so `bindgen` is able to run `Bindings::generate` multiple times with the same user input if the `generate_static_inline` option is enabled and `GenerateError::ShouldRestart` is returned by `Bindings::generate`. This is done to eventually solve rust-lang#1090 which would require to check for any static inline functions and generate a new header file to be used as an extra input and run `Bindings::generate` again.
This adds a mechanism so `bindgen` is able to run `Bindings::generate` multiple times with the same user input if the `generate_static_inline` option is enabled and `GenerateError::ShouldRestart` is returned by `Bindings::generate`. This is done to eventually solve rust-lang#1090 which would require to check for any static inline functions and generate a new header file to be used as an extra input and run `Bindings::generate` again.
* Run `Bindings::generate` again if required. This adds a mechanism so `bindgen` is able to run `Bindings::generate` multiple times with the same user input if the `generate_static_inline` option is enabled and `GenerateResult::ShouldRestart` is returned by `Bindings::generate`. This is done to eventually solve #1090 which would require to check for any static inline functions and generate a new header file to be used as an extra input and run `Bindings::generate` again.
If bindgen finds an inlined function and the `--generate-inline-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-inline-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
integration test: document the GH issue integration test (macro): same order in impl as the trait for consistency integration test: move each setup into its own function, just to save face inline static func integration test
- Because directory structure is confusing to the author of this commit rust-langGH-1090
test(static inlined): pretty print the diff Issue: rust-langGH-1090 test(static inlined): refactor paths once again - Because directory structure is confusing to the author of this commit rust-langGH-1090 test(static inlined): refactor test files - Expected files should be under tests/expectations/generated - Remove extern_stub.h because we can reuse the header from generate-extern-functions.h test(static inlined): diff test; generated files refactor(static inlined): integration test Issue: rust-langGH-1090 rust-langGH-1090: Integration tests integration test: document the GH issue integration test (macro): same order in impl as the trait for consistency integration test: move each setup into its own function, just to save face inline static func integration test resolve accidental conflict
If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes rust-lang#1090.
test(static inlined): pretty print the diff Issue: rust-langGH-1090 test(static inlined): refactor paths once again - Because directory structure is confusing to the author of this commit rust-langGH-1090 test(static inlined): refactor test files - Expected files should be under tests/expectations/generated - Remove extern_stub.h because we can reuse the header from generate-extern-functions.h test(static inlined): diff test; generated files refactor(static inlined): integration test Issue: rust-langGH-1090 rust-langGH-1090: Integration tests integration test: document the GH issue integration test (macro): same order in impl as the trait for consistency integration test: move each setup into its own function, just to save face inline static func integration test resolve accidental conflict
* Generate extern wrappers for inlined functions If bindgen finds an inlined function and the `--generate-extern-functions` options is enabled, then: - It will generate two new source and header files with external functions that wrap the inlined functions. - Rerun `Bindings::generate` using the new header file to include these wrappers in the generated bindings. The following additional options were added: - `--extern-function-suffix=<suffix>`: Adds <suffix> to the name of each external wrapper function (`__extern` is used by default). - `--extern-functions-file-name=<name>`: Uses <name> as the file name for the header and source files (`extern` is used by default). - `--extern-function-directory=<dir>`: Creates the source and header files inside <dir> (`/tmp/bindgen` is used by default). The C code serialization is experimental and only supports a very limited set of C functions. Fixes #1090. --------- Co-authored-by: Amanjeev Sethi <aj@amanjeev.com>
https://github.com/intelxed/xed has a bunch of inline functions as part of its interface. In order to make the xed bindings usable (valarauca/xed-sys#1) we need to export them somehow. If bindgen could generate C code that just wraps the static inline functions we would be able to use bindgen to generate bindings to that code which would solve the problem.
The text was updated successfully, but these errors were encountered: