How to handle pthread platform differences with bindgen generated code?

I am trying to create a sys-library crate libindigo-sys for INDIGO using bindgen.

So far it works on Mac, but when I try to compile the rust libindigo wrapper library on Linux, I run into the following problem:

error[E0308]: mismatched types
  --> src/server.rs:23:17
   |
23 |         thread: ptr::null_mut(),
   |                 ^^^^^^^^^^^^^^^ expected `u64`, found `*mut _`
   |
   = note:     expected type `u64`
           found raw pointer `*mut _`

Evidently the pthreads are managed differently on Linux and Mac, no surprise there.

The error above relates to this snippet:

    let mut entry = indigo_server_entry {
        name: name,
        host: host,
        port: port,
        connection_id: 0,
        thread: ptr::null_mut(), // <-- bindgen on Mac produces a pointer, not an u64
        thread_started: false,
        socket: 0,
        protocol_adapter: ptr::null_mut(), 
        last_error: [0; 256],
        shutdown: false,
    };

Note that I only need to create instances of this struct and provide it to various C functions, I do not need to manipulate these threads in my Rust code.

Question is, how do I manage this in my wrapper code?

An alternative is to not handle it and tweak bindgen's code generation.

A quick hack for it could be to use std::mem::zeroed() which will give you a zero value for pointers and integers.

You could also try defining types and default values for it in Rust, using #[cfg(target_os = "macos")] and similar (see cfg_if), if the types change predictably on the platforms you support.

If the required type is exported by the C headers as a typedef, then bindgen should generate it. If there isn't a typedef, you could make one yourself by including original .h files in your wrapper.h.

If the types are too C-specific or too platform-specific, you could write a C function for initializing this struct, and build and link that C code as part of your sys crate.

1 Like

This "quick hack" works perfectly for the Mac/Linux difference, will be interesting to know when what happens when I test it on Windows...

You could also try defining types and default values for it in Rust, using #[cfg(target_os = "macos")] and similar (see cfg_if), if the types change predictably on the platforms you support.

Would this work though?

The code generated on a Mac requires a ptr::null_mut and on Linux, the bindgen code requires a u64 integer instead.

Note that I don't really care about the field as long as it gets intialised to zero or null, whatever is suitable on the platform. The C code will set it to the correct platform-specific value when the server is starting.

If the required type is exported by the C headers as a typedef, then bindgen should generate it. If there isn't a typedef, you could make one yourself by including original .h files in your wrapper.h .

The type does get generated, the issue is that bindgen generates (slightly) different code on Mac and Linux.

If the types are too C-specific or too platform-specific, you could write a C function for initializing this struct, and build and link that C code as part of your sys crate.

This would be the very last resort for me, but it is a good and valid option I think. Might be the cleanest although I would have to include custom c-code in my Rust crate instead of just relying on the upstream lib.

Thanks a lot for the pointers, they helped me to move on to the next issue regarding linking the static lib file...