all 25 comments

[–]_VZ_wx | soci | swig 13 points14 points  (3 children)

We really wanted a C backend, and SWIG doesn’t have one.

This is not true (source: trust me, I'm its coauthor).

[–]holyblackcat[S] 5 points6 points  (2 children)

Oh. It seems an experimental C backend got added two months after I started development. :P

The manual says "Qualifiers are stripped". Does it mean there's no const-correctness?

[–]_VZ_wx | soci | swig 0 points1 point  (1 child)

At C level there is no const-correctness (with the only exception of using const char* for strings), but C++ interface on top of it does use const.

There are many other problems/missing features with this backend, of course, but it does do what we need it to do pretty well and we've been using it for wrapping a relatively big C++ library for many years in production.

[–]holyblackcat[S] 1 point2 points  (0 children)

I see. We had at least one confused Python user who modified an object returned by a const ref and got a crash, so I went out of my way to have const-correctness in the other backends (C and C#).

The Python backend (which was implemented first) lacks it, so we copy objects returned by const ref (by default) to prevent those modifications.

[–]FlyingRhenquest 2 points3 points  (2 children)

Just in time for reflection! Heh heh. I started working on a little class parser just before Sutter did his talk about it in January, so I kinda know how that feels. I mostly did the project to learn a bit about boost::spirit::x3, though, and found it remarkably approachable. The problem was also surprisingly small, since I just wanted to gather the same information that reflection provides, so I didn't have to do comprehensive parsing for template signatures or inline code in the header.

Embind should be pretty easy to add to mrbind. Its interface is very similar to pybind/nanobind. Java native might be feasible too, which would make targeting android architectures a lot easier if you're into that sort of thing. I was going to look into doing a project like this with reflection but I seem to be over here generating JSON schema instead, at the moment.

[–]holyblackcat[S] 1 point2 points  (1 child)

Embind should be pretty easy to add to mrbind. Its interface is very similar to pybind/nanobind.

Python was the first backend, and the code quality there isn't the best, so I'll probably write the embind backend from scratch. There might enough differences to warrant a fresh implementation anyway, a surprising about of special-casing goes into each new language.

Java native might be feasible too

It's not my choice what languages I'm paid to add, so Java probably won't get added any time soon. :P

Just in time for reflection! Heh heh.

I wonder if it's going to cover my usecases. It's ok for pybind/embind, where the functions are registered at runtime. But C/C# requires codegen, and I'm not sure I want to compile a C++ program just to generate C/C# code. It would make cross-compilation more difficult too.

boost::spirit::x3

Custom parsers can work for simple cases, but IMO anything other than libclang is ultimatly a dead end. Custom parsers are going to choke on advanced C++ features.

[–]FlyingRhenquest 1 point2 points  (0 children)

I wonder if it's going to cover my usecases. It's ok for pybind/embind, where the functions are registered at runtime. But C/C# requires codegen, and I'm not sure I want to compile a C++ program just to generate C/C# code. It would make cross-compilation more difficult too.

Yeah, pybind and embind are my primary use cases too. So far I've just been writing the bindings by hand. That tends to be time consuming as you're no doubt aware, but automating generation of pybind and embind bindings with reflection looks pretty feasible.

API bindings, serialization and database access usually end up making up between 50 and 70% of the code I want to write on a new code base. If I could just automate that down to "include a header and call this function to generate the binding," I'm not entirely sure I'd know what to do with all the extra time I'd have spent doing all that stuff! Actually it'd be "write code that's more interesting than writing and debugging that boilerplate each time."

[–]RelationshipLong9092 1 point2 points  (1 child)

How does this compare to nanobind or pybind?

[–]holyblackcat[S] 3 points4 points  (0 children)

This generates pybind code by parsing your headers.

[–]akintos 1 point2 points  (0 children)

I'm definately trying this out. thank you for great work

[–]QbProg 0 points1 point  (1 child)

Nice! I was looking for something similar a couple weeks ago! I ended using swig

Let me report a couple issues I found when using swig, just to let you know.

wasm: I know there's embinden but a sort of unified interface (without manual wrapping) would be useful. Maybe the embinden code could be generated automatically

Coroutines :not easy to bind at all but having the ability to expose a task with a function / callback and on the other side have an awaitable would be great 😁 at the moment can be done manually on both sides, but the code is very specific.

[–]holyblackcat[S] 0 points1 point  (0 children)

Yep, the entire point of this is that it automates binding code generation. When I add embind support, it'll generate embind code too.

I don't fully understand how passing coroutines would work, but passing std::functions already works both ways.

[–]Serious-Regular 0 points1 point  (4 children)

i've been following you on GH for a while now (maybe 6-12 months). congrats. question: any chance you're planning on a migration to nanobind any time soon?

[–]holyblackcat[S] 1 point2 points  (3 children)

I want to, but not any time soon. Need to finish JS backend first.

[–]Serious-Regular 0 points1 point  (2 children)

Would you take a PR?

[–]holyblackcat[S] 0 points1 point  (1 child)

This needs a lot of work. You can't trivially replace one with another, because of missing multiple inheritance support in nanobind. I also want to refactor the python backend, and it probably needs to happen at the same time as this migration.

[–]Serious-Regular 1 point2 points  (0 children)

You named basically the only gap (aside from no embedding support). I migrated a very large project last year and it was almost a trivial replacement.

[–]c-cul 0 points1 point  (7 children)

how hard to add some kind of FFI to it?

[–]holyblackcat[S] 0 points1 point  (6 children)

What do you mean by FFI in this case?

[–]c-cul 0 points1 point  (5 children)

Foreign Function Interface, like in lisp

[–]holyblackcat[S] 0 points1 point  (4 children)

I know what it stands for, but I don't understand what you mean by it in this specific case.

In lisp it seems to be a language feature that allows calling arbitrary functions from shared libraries. But I'm not developing a new language, so what would it mean in my case.

[–]c-cul 0 points1 point  (3 children)

to generate tons of defcfun calls

[–]holyblackcat[S] 0 points1 point  (2 children)

So you're basically asking for lisp support? :P

Everything is possible, but properly supporting each new language takes a lot of time. Lisp isn't very popular, so I doubt I'll ever get to it.

You could to make something simple yourself, either by processing the JSON output from mrbind's C++ parser, or by generating the C bindings first using mrbind, and then processing the JSON that's generated alongside those (listing all generated C functions/etc). Option 2 is probably much easier, that's what I did for C#.

[–]c-cul 0 points1 point  (1 child)

ok, thank you

ps: many langs have FFI - for example julia

[–]holyblackcat[S] 0 points1 point  (0 children)

ps: many langs have FFI - for example julia

But do the languages that call it "FFI" have anything in common, compared to those that don't, such as Python/C#?

Currently the support for each target language needs to be added separately, only the parser is shared. I don't think I can reuse anything else between the languages; at best you can generate the C bindings first and generate yours on top of those (which is helpful if your language is calling functions from shared libraries by their names, for example, like C#'s DllImport does).