rust-lang / rust-bindgen

Automatically generates Rust FFI bindings to C (and some C++) libraries.
https://rust-lang.github.io/rust-bindgen/
BSD 3-Clause "New" or "Revised" License
4.23k stars 679 forks source link

Convert `pub type __u8 = ::std::os::raw::c_uchar;` to `u8` (native) Rust types #2784

Closed VariableExp0rt closed 3 months ago

VariableExp0rt commented 3 months ago

This is more of a question than an issue. Is there currently a way to replace the "reserved for the implementation" types that are prefixed with a double underscore into their Rust native counterparts (I use that term loosely as I realise they will not exactly the same)?

I am new to bindgen, so it might be that this is by design. Looking at https://github.com/spacejam/rio/blob/master/src/io_uring/kernel_types.rs#L35, I see this has probably been hand crafted/modified, but I was wondering if there is anyway to do this with the library API?

Thanks!

Input C/C++ Header

/*
 * IO submission data structure (Submission Queue Entry)
 */
struct io_uring_sqe {
    __u8    opcode;     /* type of operation for this sqe */
    __u8    flags;      /* IOSQE_ flags */
    __u16   ioprio;     /* ioprio for the request */
    __s32   fd;     /* file descriptor to do IO on */
    union {
        __u64   off;    /* offset into file */
        __u64   addr2;
        struct {
            __u32   cmd_op;
            __u32   __pad1;
        };
    };
    union {
        __u64   addr;   /* pointer to buffer or iovecs */
        __u64   splice_off_in;
        struct {
            __u32   level;
            __u32   optname;
        };
    };
    __u32   len;        /* buffer size or number of iovecs */
    union {
        __kernel_rwf_t  rw_flags;
        __u32       fsync_flags;
        __u16       poll_events;    /* compatibility */
        __u32       poll32_events;  /* word-reversed for BE */
        __u32       sync_range_flags;
        __u32       msg_flags;
        __u32       timeout_flags;
        __u32       accept_flags;
        __u32       cancel_flags;
        __u32       open_flags;
        __u32       statx_flags;
        __u32       fadvise_advice;
        __u32       splice_flags;
        __u32       rename_flags;
        __u32       unlink_flags;
        __u32       hardlink_flags;
        __u32       xattr_flags;
        __u32       msg_ring_flags;
        __u32       uring_cmd_flags;
        __u32       waitid_flags;
        __u32       futex_flags;
        __u32       install_fd_flags;
    };
    __u64   user_data;  /* data to be passed back at completion time */
    /* pack this to avoid bogus arm OABI complaints */
    union {
        /* index into fixed buffers, if used */
        __u16   buf_index;
        /* for grouped buffer selection */
        __u16   buf_group;
    } __attribute__((packed));
    /* personality to use, if used */
    __u16   personality;
    union {
        __s32   splice_fd_in;
        __u32   file_index;
        __u32   optlen;
        struct {
            __u16   addr_len;
            __u16   __pad3[1];
        };
    };
    union {
        struct {
            __u64   addr3;
            __u64   __pad2[1];
        };
        __u64   optval;
        /*
         * If the ring is initialized with IORING_SETUP_SQE128, then
         * this field is used for 80 bytes of arbitrary command data
         */
        __u8    cmd[0];
    };
};

Bindgen Invocation

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .allowlist_type("([iI][oO]|[iI][oO]_[uU])[rR][iI][nN][gG].*")
        .allowlist_var("^IORING.*")
        .formatter(bindgen::Formatter::Rustfmt)
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .layout_tests(false)
        .generate()
        .expect("Unable to generate bindings");

Actual Results

pub type __u8 = ::std::os::raw::c_uchar;
pub type __u16 = ::std::os::raw::c_ushort;
pub type __s32 = ::std::os::raw::c_int;
pub type __u32 = ::std::os::raw::c_uint;
pub type __u64 = ::std::os::raw::c_ulonglong;

#[repr(C)]
pub struct io_uring_sqe {
    pub opcode: __u8,
    pub flags: __u8,
    pub ioprio: __u16,
    pub fd: __s32,
    pub __bindgen_anon_1: io_uring_sqe__bindgen_ty_1,
    pub __bindgen_anon_2: io_uring_sqe__bindgen_ty_2,
    pub len: __u32,
    pub __bindgen_anon_3: io_uring_sqe__bindgen_ty_3,
    pub user_data: __u64,
    pub __bindgen_anon_4: io_uring_sqe__bindgen_ty_4,
    pub personality: __u16,
    pub __bindgen_anon_5: io_uring_sqe__bindgen_ty_5,
    pub __bindgen_anon_6: io_uring_sqe__bindgen_ty_6,
}

Expected Results

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct io_uring_sqe {
    pub opcode: u8,
    pub flags: u8,
    pub ioprio: u16,
    pub fd: s32,
    pub __bindgen_anon_1: io_uring_sqe__bindgen_ty_1,
    pub __bindgen_anon_2: io_uring_sqe__bindgen_ty_2,
    pub len: u32,
    pub __bindgen_anon_3: io_uring_sqe__bindgen_ty_3,
    pub user_data: u64,
    pub __bindgen_anon_4: io_uring_sqe__bindgen_ty_4,
    pub personality: u16,
    pub __bindgen_anon_5: io_uring_sqe__bindgen_ty_5,
    pub __bindgen_anon_6: io_uring_sqe__bindgen_ty_6,
}
emilio commented 3 months ago

It is intentional that we don't remove typedefs by default, unless very specific (e.g. we do detect standard uint8_t and so).

You could do this manually by doing something like:

.blocklist_type("__u8")
.raw_line("pub type __u8 = u8;")

Or so, tho, right?

VariableExp0rt commented 3 months ago

@emilio I could definitely do that, I just didn't know whether I was missing something. Thanks for the pointer, I'll try this!

emilio commented 3 months ago

Yeah we don't assume anything other than standard types generally, so that seems like the best way to go. No worries!

VariableExp0rt commented 3 months ago

@emilio do you know why none of the _bindgen_anon fields that are either anonymous unions or structs and point to new __bindgen_ty types are not Copy or Clone derivable?

    pub inner1: io_uring_sqe__bindgen_ty_1,
#[repr(C)]
pub struct io_uring_sqe__bindgen_ty_1 {
    pub off: __BindgenUnionField<__u64>,
    pub addr2: __BindgenUnionField<__u64>,
    pub inner1: __BindgenUnionField<io_uring_sqe__bindgen_ty_1__bindgen_ty_1>,
    pub bindgen_union_field: u64,
}
emilio commented 3 months ago

That should work, if you could file an issue with a reduced test-case it'd be appreciated.

VariableExp0rt commented 3 months ago

@emilio as requested https://github.com/rust-lang/rust-bindgen/issues/2785.