Itseez/opencv — pull request #1600 by arjuncomar (2013-10-10 21:09:09+00:00)
Title: Automatically Generated C Wrappers and Haskell Bindings for C++ API

C Wrappers
----------

The C wrappers are generated in `genc.py` via a parsed header representation provided by
`modules/python/src2/hdr_parser.py`. It is this parser that actually makes this project possible, though a more complete approach (perhaps via gcc-xml) to actually parse the C++ syntax tree and transform it into
C wrappers would probably be better.

These wrappers are not meant to be an API to the programmer,
but rather hooks for other languages like Haskell that can call C via an FFI but cannot call
C++ directly due to name mangling. For example, C++ objects are passed around as raw pointers,
and memory management is not handled by these wrappers. The intention is that the binding platform
will hook malloc and free to do memory management correctly -- the Haskell runtime provided by GHC
does a wonderful job of this. Moreover, copying is kept to a minimum, and objects are exposed primarily via their methods.

The transformation from C++ method to C wrapper function is as follows:

/RetType/ /Classname/::/methodCall/(/args.../) -> /RetType/ cv_/Classname/_/methodCall/(/Classname/* self, args...)

Constructors are provided similarly as:

Classname* cv_create_/Classname/(/args.../)

And #define constants are transformed as follows:

cv::/module/::/CONSTANT/ -> CV_/MODULE/_/CONSTANT/0

The 0 is appended because some (but not all) of these constants are exported with the same name by OpenCV already, and I wanted to avoid the warnings. A more thorough approach would track these constants and drop the ones that are already defined this way in the headers.

The automatically generated portions of these wrappers are provided in `opencv_generated.hpp` and
`opencv_generated.cpp` for headers and source respectively. Some major classes are not parsed
correctly by `hdr_parser.py` so these types are manually wrapped and show up in explicitly named
headers and source files (e.g. `mat.hpp`/`mat.cpp`). A header called `opencv.h` includes both the
automatically generated header and the manual headers and is located at `include/opencv2/opencv.h`.
The other headers are installed to `include/opencv2/c/`.

I hope to get these wrapped functions into the OpenCV library proper because I imagine many people would find
them useful. Most languages can interoperate with C, but very few can interoperate directly with C++.

Classes are not converted to structs and instead the wrapper deals with them as opaque pointers. Again, the
intention is not to create a fully featured C API for the programmer but rather to allow bindings to languages that cannot interop with C++.

Haskell Bindings
----------------

The low level bindings are provided via bindings-dsl macros that call the C functions directly. The C -> Haskell
translation is as follows:

Ret* cv_wrapped_function(Arg1* arg1, Arg2 arg2, int arg3...) ->
c'cv_wrapped_function :: Ptr C'Arg1 -> C'Arg2 -> CInt ... -> IO (Ptr Ret)

Function pointers are also available as `p'cv_wrapped_function :: FunPtr`.

Similar to the C API, these functions are not meant to be used directly. They're all stuck in IO and provide a rather inconvenient API. The programming model feels a little worse than it would trying to use those wrapped functions in C. A higher level library that builds on these wrappers is required for actual use.

Types are exposed primarily as opaque pointers that you can interact with via the provided functions. Classes are transformed into types as:

/Classname/ -> C'/Classname/

Beyond that, there's not much to say. The same caveats apply as with the C bindings. They are not intended for direct use but instead as an API for library developers.

Missing Types
---------------------

The automatic approach fails to wrap several rather important types (Mat, Point, Rect, Size, etc.). These types are wrapped manually and provided in separate headers. There are still several more types that need to be wrapped in this manner (Vec and possibly Matx are probably the most important of these). I plan to continue wrapping these types over the next couple of weeks and improving the interface to them as I go.

Documentation and Tests
-------------------------------------

This pull request is primarily intended to get the conversation started with respect to these wrappers and bindings. I don't actually expect this request to get merged immediately, especially because there are still some important things outstanding -- namely, documentation and tests. The Haskell bindings have documentation generated for them and I've put those docs in the [gh-pages](http://arjuncomar.github.io/opencv/) branch of my fork. Of course, these docs don't yet pull information from the reference manual and so they're about as useful as just reading the source file. At some point in the near future I plan to generate docs for both C and Haskell with documentation pulled from the reference manual or some similar source. I also could use some test cases. I've thus far been testing these bindings while developing a higher level Haskell library that builds on top of these bindings. However, this is not an ideal test case for inclusion into the main repo. Recommendations for good test cases are very welcome, as are pull requests.

Issues
----------

The Haskell bindings fail to generate correctly with make target dependency issues when cmake is called the first time. Calling cmake a second time resolves this issue.

That is, if a new build directory is created at `/build`, then

cmake .. && cmake ..

is required to generate a makefile that can actually create and compile the Haskell bindings. Just calling cmake once causes a dependency issue with make unable to locate one of the library headers. I have not had time to investigate this issue properly.

Technical Comments
------------------------------

Haskell is a rather complicated language to compile and link correctly and this issue is compounded by the need to interface with a C and C++ library. Therefore, rather than attempt to reconstruct a Haskell build system within CMake, I've elected to just call out to the standard Haskell build tool `cabal-install`. Also because the Haskell bindings have a (single) dependency within the Haskell package ecosystem, it is necessary to delay compilation of these bindings until `cabal-install` can be called as the correct user (the one `make install` is called as). Therefore, the bindings are compiled and installed in one go when `make install` is called.

Maintenance
-------------------

I plan to continue developing these bindings and maintaining them for the forseeable future. I would greatly appreciate issues submitted to my fork or to the (now-defunct) opencv-raw repository where I'll get notified about them immediately (I'll be able to get you fixes faster that way). I'll also watch the issues page with the main repo for any issues with these wrappers or bindings.