rust-bindgen icon indicating copy to clipboard operation
rust-bindgen copied to clipboard

Definitions of static or macro-defined arrays are not emitted

Open Deewiant opened this issue 7 years ago • 4 comments

Input C Header

#define MACRO_ARRAY {1, 2}

static const int static_const_array[] = {3, 4};

Bindgen Invocation

$ bindgen input.h

Actual Results

extern "C" {
    #[link_name = "\u{1}static_const_array"]
    pub static mut static_const_array: [::std::os::raw::c_int; 2usize];
}

(The presence of the mut is #511, it's not the point of this issue but I'm just noting that that's a separate incorrect thing here.)

Expected Results

As it is, neither array can be used with bindgen alone. MACRO_ARRAY is not emitted and attempting to use static_const_array will result in a link error, because there is no definition, only a declaration.

I was hoping to see at least:

static static_const_array: [::std::os::raw::c_int; 2usize] = [3, 4];

And ideally:

// Inferred as c_int based on the types of 1 and 2
static MACRO_ARRAY: [::std::os::raw::c_int; 2usize] = [1, 2];

static static_const_array: [::std::os::raw::c_int; 2usize] = [3, 4];

I figure that cases like MACRO_ARRAY are difficult in general, relating to issues like #316. But if at least the static_const_array case would work, it could be used as a simple workaround for the macro support.

Workaround

As it is, one has to write and compile some C (typically involving the cc crate) that provides a symbol to hold the array value, and in the non-macro case a way of initializing it because C can't do it at compile time. For example:

#include <string.h>
#define MACRO_ARRAY {1, 2}
static const int static_const_array[] = {3, 4};

const int my_macro_array[] = MACRO_ARRAY;

int my_static_const_array[sizeof(static_const_array) / sizeof(static_const_array[0])];
void my_static_const_array_init(void) {
   memcpy(my_static_const_array, static_const_array, sizeof static_const_array);
}

And then in the bindgen stub declare e.g.:

const int my_macro_array[sizeof((int[])MACRO_ARRAY) / sizeof(int)] = MACRO_ARRAY;

extern int my_static_const_array[sizeof(static_const_array) / sizeof(static_const_array[0])];
extern void my_static_const_array_init(void);

And finally, arrange a way of calling my_static_const_array_init when needed.

Needless to say, this is quite painful. :-) I'm open to better approaches, this is just the most straightforward thing off the top of my head.

Deewiant avatar Mar 02 '18 17:03 Deewiant

The clang constant evaluation stuff doesn't work for arrays at all afaict, so this would need upstream changes to libclang to be fixable.

emilio avatar Mar 02 '18 17:03 emilio

You're right. I filed it upstream: https://bugs.llvm.org/show_bug.cgi?id=36576

Otherwise, I suppose #297 would provide a fix, but it's a bigger undertaking.

Deewiant avatar Mar 02 '18 18:03 Deewiant

Sharing that the LLVM bug moved to github: https://github.com/llvm/llvm-project/issues/35924

I've run into this bug as well, where some constant structures are defined in headers. Would really like to not have to manually copy that data over

Eg: Definition in header: https://github.com/giantcow/nvcodec-rust/blob/294813153b80fad3984c1fde065469f104b19eb2/nvenc-sys/include/nvEncodeAPI.h#L140-L141 bindgen blocklist: https://github.com/giantcow/nvcodec-rust/blob/294813153b80fad3984c1fde065469f104b19eb2/nvenc-sys/build.rs#L19 Manual definition: https://github.com/giantcow/nvcodec-rust/blob/294813153b80fad3984c1fde065469f104b19eb2/nvenc-sys/src/lib.rs#L25-L30

giantcow avatar Aug 12 '25 18:08 giantcow

I found an ugly workaround, but it works without manually copying anything. In my case, I needed to generate this PFRES_NAMES macro. The values can be obtained via the ParseCallbacks::modify_macro method and appended to the generated file. A complete example is in this build.rs.

mxk avatar Oct 31 '25 02:10 mxk