cbindgen icon indicating copy to clipboard operation
cbindgen copied to clipboard

Using libc::[some c-struct] in function gets export without struct keyword

Open johalun opened this issue 4 years ago • 6 comments

Hi

I'm writing a Rust library with C interface where I'm using libc structs in function arguments. The generated header file then ends up with type like "sockaddr" instead of "struct sockaddr".

I solved this by renaming like this

[export.rename]
"sockaddr" = "struct sockaddr"

Is this the way to go or am I missing a "nicer" solution?

johalun avatar Jul 06 '20 03:07 johalun

What is the whole configuration you're using?

emilio avatar Jul 06 '20 15:07 emilio

autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
language = "C"
includes = []
no_includes = false
sys_includes = ["stdint.h", "sys/epoll.h", "sys/socket.h"]

[parse]
parse_deps = false

[export.rename]
"epoll_event" = "struct epoll_event"
"sockaddr" = "struct sockaddr"

johalun avatar Jul 06 '20 15:07 johalun

Hmm, right... I think the issue is that cbindgen is not parsing epoll_event / sockaddr so it doesn't really know it's a struct rather than e.g. an enum.

We could conceptually get some knowledge about libc in cbindgen, but that seems a bit brittle and lacking that... I don't think there's an straight-forward solution.

Does using parse_deps = true get the right info?

emilio avatar Jul 06 '20 16:07 emilio

Does using parse_deps = true get the right info?

Nope... It's fine, it's a minor issue and renaming works fine. A bigger issue with build.rs is that cbindgen runs before rustc so any build errors are detected by cbindgen instead of rustc so I moved it to a Makefile instead. I wish we had pre/post build script support in cargo...

johalun avatar Jul 06 '20 17:07 johalun

Yeah... in practice in Firefox we use cbindgen from the cli interface for these kinds of things.

emilio avatar Jul 07 '20 14:07 emilio

I was unable to get renaming working because cbindgen has apparently become clever in the last few years and knows that e.g. struct in_addr is not a valid name and so replaces the space with an underscore, making it struct_in_addr in my header.

I have managed to 'trick' cbindgen into working by:

lib.rs

/// cbindgen:no-export=true
#[allow(non_camel_case_types, unused)]
struct in_addr;

fn x() -> libc::in_addr { ... }

cbindgen then:

  • sees x requires an in_addr definition
  • spots an opaque (i.e. not repr(C)) struct that matches in_addr and so knows it's a struct
  • does not actually emit an opaque struct declaration (i.e. typedef struct in_addr in_addr;) because of the no-export annotation

Which ends up with correct usage of in_addr without creating a definition that conflicts with the header file.

no-export was undocumented, which I have a PR to fix at #897.

Note that this workaround may break if #7 gets fixed.

aidanhs avatar Nov 10 '23 18:11 aidanhs