rust-bindgen
rust-bindgen copied to clipboard
Improve macro defined constants to recognize #define CONSTANT ((int) 1)
In the header files I am trying to make bindings for, some constants are defined like this:
#define kOfxStatFailed ((int)1)
#define kOfxStatErrFatal ((int)2)
// ...
Can this pattern be supported? Maybe I can attempt to add this if I get some guidance :)
This can certainly be supported, though it'd be kind of a one-off.
Indeed I think this eventually worked (by chance) because at one point we tried to find just the first integer literal token.
I think the best approach for this is something like:
- Stripping parentheses of the
cexpr_tokens
variable insrc/ir/var.rs
. - Try to split a leading cast on those tokens (something like: First one is punctuation and the character
b'('
, next token is a literal and a well known type (let's support onlyint
to begin with, for example), and then another punctuation with theb')'
char. - With that stripped, the rest of the code should just work. Also, we can detect what the cast is, and save it to generate the correct type, that'd be a plus :)
Do you want to try implementing it? I'm not sure I'll find the time myself in the near term. If you want, happy to elaborate more if needed :)
Yes, I will give it a try :) I'll let you know if I get stuck.
Can't we just make cexpr support casts?
I think it would be better too. The code I wrote felt out of place and it would be better to handle all macro const stuff in the same place.
Yeah, that'd work better. I've also just realized we can't just strip wrapping parentheses since they can change the precedence of operators.
I have a similar case. Anyone knows how I can use the following in Rust in the meantime?
#define GSS_C_NO_NAME ((gss_name_t) 0)
#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
I guess you'd need to define them manually :/
@brunoqc if gss_foo_t
are typedefs of pointers, then this should work:
0 as *mut _
If they are typedefs of some kind of integer type, then this should work:
0 as _
Otherwise, you'll need to use std::mem::transmute
(maybe with lazy_static
if you want it to be a global):
use std::mem;
let no_name: gss_name_t = unsafe { mem::transmute(0) };
I have a rather stupid idea. Which can 'shoot' tho. For each macro definition, construct a stub C++ file
#include "source_header.h"
const auto CONSTANT = MACRO;
Then force CLang to process it and give type and value of CONSTANT
. If it doesn't compile, then it's not a macro constant.
It may be rather slow - but I'd presonally wait once to have proper constants.
I imagine the following could never work with this
#define ECL_T ((cl_object)(cl_symbols+1))
where cl_symbols is an array holding structs.
Bindgen team: tag this with help wanted?
@ristew We currently don't support handling anything but literals, not including struct initializers. Never say never, but I wouldn't expect support for things like that any time soon.
Currently, I have the following macro in C, which is completely get ignored by the bindgen, is there anyway to create it automatically?
#define SPDK_NOTICELOG(...) \
spdk_log(SPDK_LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define SPDK_WARNLOG(...) \
spdk_log(SPDK_LOG_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define SPDK_ERRLOG(...) \
spdk_log(SPDK_LOG_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__)
Supporting #define
function calls, especially with printf-style formatting, is probably not happening anytime soon.
@jethrogb Thanks for the reply. I'm wondering if that's something I can do manually in Rust? If so, I can write them on my own but I can't find some proper example on how to do so.
Thanks much!
@xxks-kkk I'd consider using the log
crate for your rust code. You can then add a logger
implementation that forwards to spdk_log
if you need to, but it'd probably be unnecessary.
I just hit this issue myself:
/* Used as the device ID for mouse events simulated with touch input */
#define SDL_TOUCH_MOUSEID ((Uint32)-1)
any news here? would also be nice to specify what types I want for those defines, a lot of time it's i32
and not u32
Perhaps an option to have define values be emitted on the rust side as macros that spit out literals, then the literals can fit into any type
#define foo 1
becomes
macro_rules! foo { () = { 1 } }
On one hand that's somewhat more correct (Altough Rust's literal rules don't match C's) on the other that will bloat everything up.
And might ruin compile time?
I can't imagine it would ruin compile time. It's the same cost as a single token inline function basically.
But we also don't need it always in macro form, just for specific designated elements that need to be both signed and unsigned.
The right way to specify a type is using static const
s, fwiw: static const int32_t FOO = 1;
.
There's a way to specify the type for the #define
: https://github.com/rust-lang/rust-bindgen/blob/1c31f29e4e5d514e6df14d2e82662de7e947c2af/src/callbacks.rs#L34
The right way to specify a type is using
static const
s, fwiw:static const int32_t FOO = 1;
.There's a way to specify the type for the
#define
:https://github.com/rust-lang/rust-bindgen/blob/1c31f29e4e5d514e6df14d2e82662de7e947c2af/src/callbacks.rs#L34
I looked into the code now and the logic seem right but it looks like it doesn't work properly. the only place it's called is: https://github.com/rust-lang/rust-bindgen/blob/master/src/ir/var.rs#L210 which then calls https://github.com/rust-lang/rust-bindgen/blob/master/src/ir/var.rs#L117
~~which seem like it will choose i32
if less then max or u32
if more but in practice that's not what happens:~~
test.h
:
#define AAA 5
bindgen test.h
output:
/* automatically generated by rust-bindgen */
pub const AAA: u32 = 5;
As you can see it chooses u32
even though it should be i32
EDIT: I'm wrong, the logic there is flawed. it chooses i32
only if it's a negative number.
Ok. While trying to come up with a function that will match more closely the C11 standard (6.4.4.1p5.) I found the following problem:
#define AAA 9223372036854775808ULL
bindgen returns:
pub const AAA: i64 = -9223372036854775808;
The problem seems to be because of the use of Wrapping(i64)
, I think the better way would be to use i128
and then have 2 algorithms, one for if it has the u
postfix another if it doesn't (not sure how that's represented in clang's AST).
Anyway this seems out of my depth currently :/ @emilio
That needs cexpr
support, basically: https://github.com/jethrogb/rust-cexpr is what we use to parse the macros and only has i64 support. It should probably at the very least return a u64 for that case.
Related: https://github.com/rust-lang/rust-bindgen/issues/1594 https://github.com/jethrogb/rust-cexpr/issues/16
There's an open PR that will improve things somewhat https://github.com/jethrogb/rust-cexpr/pull/15
I've been having this issue while implementing nintendo DS support to rust. Some registers defined in the libnds SDK aren't getting defined in rust
/*! \brief Key input register.
On the ARM9, the hinge "button", the touch status, and the
X and Y buttons cannot be accessed directly.
*/
#define REG_KEYINPUT (*(vuint16*)0x04000130)
this is one of them that does not get exposed to rust
Speaking from my experience with the GBA, it's unlikely that you'd want to use C headers for defining your MMIO anyway. Since C doesn't have repr(transparent), they also miss out on having any good level of typing on their MMIO.
Speaking from my experience with the GBA, it's unlikely that you'd want to use C headers for defining your MMIO anyway. Since C doesn't have repr(transparent), they also miss out on having any good level of typing on their MMIO.
could you elaborate ?
at the moment I've been using stuff like
pub const REG_KEYINPUT : *const u16 = 0x04000130 as *const u16;
in order to represent these defines. I then read and write them through read_volatile and write_volatile
is it a bad way to do it ?
to be honest I've more programmed in C++ before, I'm in a phase where I transition to rust. atm I'm doing a kind of 1 to 1 wrapper to the libnds sdk and I planned to make a safe wrapper after once i got the unsafe wrapper working. like they do for the 3ds with libctru-rs