I'm trying to learn C(++) library binding with cross-compiling in mind: libmodbus
The first thing I faced: how should I wrap static vs dynamic libraries? The static library seems me most universal way thinking about Cortex-M microcontrollers target. For upper-end targets the Golang way compiling all solid is affordable. But I have a problem in between -- MIPS router SoCs with 8/32M of memory.
Also, I see some disadvantage of how Nim implements C integration: the source differs in variants for static/dynamic binding. It is more logically leave all details to C compiler and build scripts, as developer every time must have a control: should he use .dll or build some single library in-app.
That's exactly what the getHeader function I'm working on does - work with build tools behind the scenes so that you don't have to. Plus everything else nimterop does to make things seamless.
That being said, as a binding author, you still need to know how to build - what flags configure needs, and what headers need to be wrapped.
Please look into the v020 branch of nimterop. If it doesn't meet your needs, I'd definitely like to understand why not.
I don't feel that some side parsing-only library is better than C preprocessor and compiler frontend.
As I replied in the other thread, nimterop does use the preprocessor but nothing beyond that since the dependency on clang was too huge. I use gcc on Linux and Windows so expecting clang to be present wasn't acceptable to me. But if you have a way to leverage gcc that works on OSX as well, then it will definitely be interesting. Of course, again we are stuck if someone uses a compiler like VC++ or something else. tree-sitter isn't perfect but very easy to distribute so that anyone can get it running quickly. Besides, it supports a variety of languages, not just C/C++ so it opens the door for even more interop.
looks like the manually processed output of c2nim was run personally (and manually) on every source code .c/.h file
The output you are referring to was automatically generated with this code. Nothing was manually done. The cImport() call does all that work. No doubt there are limitations and you can also try c2nImport() instead, but if that doesn't work then good luck. I see that's where you are with GTK and co. so I appreciate what you are facing. I routinely run into libraries that I cannot wrap due to this very limitation. But I know I can expand support to C++, Go and Rust since the AST tree-sitter gives me all the info I need but it will take time and community contributions, especially to do it quickly.
I definitely don't like large amount of magic numbers for library constants
Instead of const ABC = 123, we could easily do var ABC {.importc.}: int instead. Ideally, we could use const/let but you cannot declare them without a value so we are stuck with var.
Having the values in the wrapper make it more readable though and the nimterop method expects the wrapper to be generated on the target machine (preprocessor, etc. are target specific) so the values will be in sync with the headers anyway. Regardless, it isn't a big change if desired.