I’m thinking about generating a wrapper for a pure C library (raylib). So far I have found two options for doing that (semi-) automatically: Clang and CBindingGen.
Clang seems to be the default option, but while documentation for both is on the sparse side, CBindingGen appears to be slightly more accessible (I managed to generate and load bindings in about 30min).
Does anybody have any experience with either of them and can give me some pros and cons to help me with the decision which one to use?
If it helps at all, this is the first time I’ve heard of CBindingGen and it’s unclear from their docs why it’s being developed instead of contributing to Clang.jl (I’m sure there’s a reason, but I couldn’t find one written down)
CBindingGen.jl is based on CBinding.jl, which overcomes some limitations of Julia’s standard C interface, Clang.jl uses Julia’s standard C interface. @krrutkow can perhaps offer some more insights (albeit biased )
CBinding was necessary to more accurately support C code, but it had its quirks. CBindingGen was an alternative to Clang (which has its own quirks) that used the CBinding syntax to less manually create the bindings.
The CBinding* framework was an experimental and educational step though, and we are working on releasing a new related package this week that you all might find rather interesting.
I finally got around to giving this a try and I have to say the generated code looks super-pretty! If it works as well as it looks this is definitely a winner.
Update:
Works great save for macros and varargs (not implemented yet, as mentioned in the PR @Gnimuc linked to). Also, the library name in the .toml file needs to be a symbol (so “:libraylib” in my case).
But I can definitely work with this and the generated Julia API seems to be much nicer than CBindingGen.
The new string macro just allows users to write exactly C code, which, I think, is way better than CBinding.jl’s Julia-C-hybridized macros.
As I mentioned above, the goal of Clang.jl’s generator is to generate code that a user will write based upon Julia’s C interop docs. The goal of CBinding.jl/C.jl is to get a better user experience when working with the C interface.
And for historical reasons, the name of Clang.jl is also to some extent misleading. Clang.jl should only host a thin wrapper over libclang or even Clang, but I guess it’s too late to make the change.
Off-topic, but I’ve been waiting for #32658 to finally be merged for ages. It’s really slightly embarrassing that Julia still has no simple, straightforward way to declare mutually recursive types.
With the ‘j’ string macro option applied, Julian names are also created. So in this example you can directly use libraylib.Transform for instance.
As you mention, bindings are always generated in the c"..." symbol “namespace” to avoid name collisions (that approach is 100% foolproof). They are optionally mapped into the Julian symbol “namespace” if the user determines no name collisions will occur and requests that functionality.
Unfortunately more urgent (as in I’m actually getting paid to do them) things got in the way and will do so for a while. I still intend to get back to the raylib wrapper, but it might be a couple of months before I have the time to do so.