rust-bindgen
rust-bindgen copied to clipboard
Bindgen generates different type name for va_list on different systems
Input C/C++ Header
typedef __builtin_va_list va_list;
void foo(va_list arg);
Bindgen Invocation
$ bindgen input.h
Actual Results
- on arm64 macos
/* automatically generated by rust-bindgen 0.68.1 */
pub type va_list = __builtin_va_list;
extern "C" {
pub fn foo(arg: va_list);
}
pub type __builtin_va_list = *mut ::std::os::raw::c_char;
- on x64_64 linux
/* automatically generated by rust-bindgen 0.68.1 */
pub type va_list = __builtin_va_list;
extern "C" {
pub fn foo(arg: *mut __va_list_tag);
}
pub type __builtin_va_list = [__va_list_tag; 1usize];
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __va_list_tag {
pub gp_offset: ::std::os::raw::c_uint,
pub fp_offset: ::std::os::raw::c_uint,
pub overflow_arg_area: *mut ::std::os::raw::c_void,
pub reg_save_area: *mut ::std::os::raw::c_void,
}
Expected Results
I expect the name of this type to be the same on both systems regardless of the underlying implementation.
I can confirm this issue, any workaround?
I was trying to use https://github.com/dylanmckay/vsprintf for a function that takes const char* format, va_list args and this works as expected on arm64 but not on x64_64 linux
118 | let str = vsprintf::vsprintf(format, args).unwrap();
| ------------------ ^^^^ expected `*mut _`, found `[__va_list_tag; 1]`
| |
| arguments to this function are incorrect
|
= note: expected raw pointer `*mut _`
found array `[libpinmame::__va_list_tag; 1]`
You can test this locally
eg on aarch64
rustup target add x86_64-apple-darwin
bindgen input.h -- --target=x86_64-apple-darwin
# --target=aarch64-apple-darwin
for now I'm working around as vsprintf can handle both types
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
type VaListType = *mut crate::libpinmame::__va_list_tag;
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
type VaListType = crate::libpinmame::va_list;
pub unsafe extern "C" fn pinmame_on_log_message_callback(
log_level: u32,
format: *const ::std::os::raw::c_char,
args: VaListType,
_user_data: *const ::std::os::raw::c_void,
) {
let str = unsafe { vsprintf::vsprintf(format, args).unwrap() };
on_log_message(log_level, str);
}
Not sure if this also applies to linux/windows aarch64.
You can also use --target=... on the cargo build to build for a different architecture.
If some of the devs could confirm this is not a bug but just something we need to handle?
My packages build out the box on linux/arm64 so this seams to be just a mac thing.
While I understand this is annoying, there is not much we can do from the bindgen side as clang provides the definitions for these built-in types itself. So the fact that bindgen emits the __builtin_va_list type as an alias for [__va_list_tag; 1usize] on x86_64 is just because that's the definition that clang is exposing, the same logic applies to the aarch64 case. You could use @francisdb 's workaround or blocklist __builtin_va_list and replace it with the alias you consider appropriate.
The type name is the same in all c (even if the type is a macro). Is there any way bingen could emit a type elias that's consistent regardless of the underlying type?
So after a little bit more digging it seems the issue we have here is that on C void foo(__va_list_tag arg[1]); is just the same as void foo(__va_list_tag *arg);. A more minimal example would be
void foo(int arg[2]);
which is translated as
pub fn foo(arg: *mut ::std::os::raw::c_int);
instead of
pub fn foo(arg: *mut [::std::os::raw::c_int; 2]);
So this is a particular case of https://github.com/rust-lang/rust-bindgen/issues/1561 which was fixed by adding the --use-array-pointers-in-arguments option here https://github.com/rust-lang/rust-bindgen/pull/1564.
If I pass this flag to bindgen using the headers you provided, on linux in x86_64 I get the following output:
pub type va_list = __builtin_va_list;
extern "C" {
pub fn foo(arg: *mut va_list);
}
pub type __builtin_va_list = [__va_list_tag; 1usize];
Which I think is what you want. Let me know if this is correct or not :)
That flags changes args: *mut va_list to args: *mut __va_list_tag on x86_64 but on arm it stays as arg: mut va_list.
yeah but the name of the type is the same, isn't that what you wanted?
No, I have my own rust function that takes a VaList then calls a c function that takes a VaList
extern "C" fn my_function(args: ?) {
bindgen_generated_function(args)
}
I need to be able to declare my function with the right type for the types to match.