Wrapping optional components
In looking at this issue, I’m not really addressing my TODO list in the correct order, but Konstantin Chugalinskiy asked a question on the subject on the wxhaskell-users mailing list. His specific question was about using wxWebConnect to provide access to a WebKit browser component from wxHaskell, but the problem is more general.
An aspect of wxWidgets which has been problematic when it comes to maintenance is that there is actually a very considerable number of valid build configurations, and this continues to increase as time passes. When we moved to the Cabalized build system six months or so ago, one change which was a consequence is that we only wrap the ‘default’ subset of wxWidgets. This has the unfortunate side-effect that some features which were previously supported are no longer available. The main among these are:
- Styled Text Control
I would prefer for these optional components to be wrapped up as separate Cabalized libraries (so if you want Styled Text Control support you would need to do something like ‘cabal install wxstc’), so started looking into the problem.
wxDirect is not a general purpose wrapper generator
The most obvious approach is to use wxdirect to generate the Haskell bindings, and this immediately causes a problem, which is this: wxdirect was really designed as a single purpose wrapper generator. It is very closely coupled to the C coding style used by the C wrappers for wxWidgets in wxHaskell, which are hand-written in a specific style. In addition, its internal design and outputs are really only intended to generate WxCore.
In the past, shelarcy made changes to wxdirect to enable it to generate Haskell bindings for the Styled Text Control, but these changes were made in a way which really supports STC only, and which still requires hand-written bindings.
Generating bindings automatically
At the moment, WxCore relies on a set of C language bindings to wxWidgets which need to be written and maintained manually. These work well, and have the considerable advantage of generally being very thin wrappers over the C++ code. The problem, however, as shown up in a couple of earlier postings to this blog, is that it is very easy for errors to creep in, and for new (or old) functions not to be wrapped.
About a year ago, on the wxhaskell-devel list there was some discussion on trying to generate the C bindings automatically. At the time, the discussions centred around using Doxygen to generate the information required to generate the C bindings. There was a proof of concept by Mads Lindstroem, using scripts written in Python to do much of the work. I have decided to see if I can make any progress in this direction (if it proves to be too much work, I’ll just make changes to wxDirect, but this will mean staying with hand-written C wrappers).
Looking at the Doxygen approach, one problem is that it seems to require a complete copy of the wxWidgets source repository (to get at the Doxygen sources) – plus I’d rather work in Haskell than Python (*) and I have never succeeded in getting *any* of the XML libraries for Haskell to work properly on my Windows development box.
(*) Nothing against Python – it is a fine language, but my spare time is very limited, and I prefer not to spend it re-learning a language I have mostly forgotten.
The most preferable solution would be to generate the wrapper code from the wxWidgets headers directly, since that would avoid transcription bugs and scale nicely to the problem of wrapping other wxWidgets components if needed. There are a couple of ways to approach this:
- gccxml generates an XML representation of the parse tree of a piece of C++ code. It suffers from a couple of issues: I couldn’t get it to build on Windows, and I’d have to get an XML library for Haskell working on Windows. It also appears not to be very actively maintained.
- SWIG is designed for exactly this sort of thing, but doesn’t support Haskell.
Now, SWIG support for Haskell would actually be pretty sweet, as it would make binding to many C++ libraries a great deal easier. I’m going to look into it – after all, how hard can it be? Probably the most significant issue to work through is that the WxCore API has been stable for a very long time now, so whatever approach to wrapping I take needs to come out with exactly what we have today (minus the bugs, obviously).