Help with Open Cascade Technology (C++) bindings

At work, we use python bindings to OCCT, which is a CAD kernel. Python can be a little slow and I thought that I would try to write some OCaml bindings as a learning exercise. What is the best way to write bindings to a C++ object oriented library? Are there any example projects that could show me how its done? Right now I am going off of this issue from the ctypes library: https://github.com/ocamllabs/ocaml-ctypes/issues/187. I also took a brief look at how ocaml pytorch bindings were done. I am not an experienced programmer, so any help/advice would be much appreciated. Thank you!

Does OCCT’s C++ API provide only entrypoints, or also callback? That is, are there places where you supply a C++ object with methods, that get invoked by OCCT ?

No callbacks. Just entrypoints as far as I know.

Are the types in the entrypoints all simple types? Or are there complex types – pointers, structs, arrays ? Does it use STL for complex-type arguments ? How is memory ownership managed across the API ?

Not all types are simple. There are a lot of complex types too. It does look like STL is used. All objects are reference counted and use a custom memory allocator. Objects that are meant to be allocated on the heap inherit from a base class that provides a field to keep track of reference counting. The memory manager has a cluster of small arrays for small objects, whose memory can be recycled. Larger objects are allocated with malloc as needed. Not sure if this is what you meant by “memory ownership”, but hope it helps.

A long while ago, I wanted to use the RocksDB C++ library. Someone else had wrappered the C API to the C++ library (a C wrapper for the C++ API) to make it accessible from OCaml, but (I forget why) I wasn’t satisfied with it. Perhaps it was for a backlevel version, or didn’t support operations I needed. In any case, the problem with the C API is that it effectively marshaled in-and-out of the C++ types into C types, and then OCaml marshaled to/from OCaml types. Lotta waste. Because some of the RocksDB structures were complicated, the C types were complicated, and memory-ownership was a PITA. Big mess.

So one day, I decided to write my own FFI generator that would work directly against the C++ API. This worked because the C++ API followed a strict memory-ownership discipline, based on the Google C++ Style Guide. It meant that even for complicated combinations of STL type-constructors, it was possible to near-automatically generate the converters to/from OCaml types.

I found this approach much simpler than trying to figure out CTypes, and partially because it involved me writing less code (once, sure, I’d written the FFI generator).

Anyway, just a thought. You can find the code at GitHub - chetmurthy/ocaml-cppffigen: C++ FFI Generator for Ocaml
As you can see, it’s nearly 4yr old. If you find this interesting, I’d be happy to get it working with modern OCaml, and if you have small examples, I could get them to work (or find out why they don’t) with this generator.

The key insight was that with C++ STL written using templates, it was possible to use template metaprogramming in a way kind of like Prolog, to select and combine the code-fragments that would do the marshaling to/from C++ and OCaml types.

2 Likes

Thank you for the help! I will take a look.

I may be missing something, but did you take a look at the Python bindings? Almost all high-level languages which do FFI, do it by binding to C libraries or C wrappers over C++ libraries. The same goes for Python. So however the Python bindings work with OCCT, is probably also how the OCaml bindings should work. Of course, the difference would be the specific syntax for doing the bindings in Python vs OCaml.

The Python bindings use SWIG. I need to read up a little more on how SWIG works, but I read that the OCaml part of SWIG is a bit outdated. Maybe there is some intermediate C output from SWIG that I could use.