A blog where I will write mostly about programming in Cocoa, Carbon, and CoreMIDI, and experiences from my ports of Emacs and XEmacs to Mac OS X.
Exception Handling for Extension Functions
Saturday October 1, 2005
Exception handling is something that one really cant do without when writing any reasonable size program or programming library. Since I have decided to write the MIDI library in C (with CoreFoundation objects), I need a way to do exception handling in C. There exist many such libraries, all based on
setjump and
longjump and C preprocessor macros.
Cexcept looks like a simple and well-tested one, with a liberal license that will serve our purpose.
I used it to write
a Python extension that shows how to use SWIGs
%exception directive to translate a C exception into a Python one. In the implementation of the wrapped function, when an exception occurs, one simply says
Throw "<static string explanation>" to raise it. The Python code can then use the standard Python exception-handling mechanism to catch that exception. When the function is called from Objective C, a hand-coded wrapper is needed to translate the C exception into an Objective C one. Such a wrapper will probably be necessary to convert C code into object-oriented Objective C code and to convert CoreFoundation parameters and return values to Cocoa Foundation ones anyway.
Modifying the
%exception definition for use with Chicken is trivial.
A C++ Wrapper for CFPropertyListRef
Friday September 30, 2005
Let me go back to explain why I am writing all these SWIG, Python, Chicken, wrapping, etc. stuffs in the past few days. I want to write a pretty good MIDI programming library. I also want everyone to use it, so its API needs to have bindings for different languages. Of course I will be using it myself in my own MIDI programs too, like version 2 of MyJazzBand, or whatever more powerful form it will evolve into.
Many of the MIDI programs that use it will likely be Cocoa programs so this library should also be callable from Objective C. If you look around, SWIG seems to be a reasonable choice for tool to automate wrapper generation. The two languages that are most important to me for use in my MIDI programs at the moment are Scheme and Python. But SWIG is not without its limitations. Support of Objective C as a source language (apart from C and C++) was dropped since revision 1.1. If a student out there is reading this, adding it back will make a nice M.Sc. project. Youll also certainly have my gratitude and that of many OS X programmers!
In the mean time, or assuming that this wont happen, the show must go on: how can I write this library and still make use of SWIG to generate all these wrappers
and support Objective C!? One way is to write C-callable functions that take and generate
CFPropertyList arguments and return values, resp. With the toll-free bridge between CoreFoundation and (Cocoa) Foundation, these functions can then be used quite conveniently from Objective C.
Another possibility is to write functions and classes in C++. To pass parameters into and results out of Objective C code, one can still make use of
CFPropertyList objects. Again, Objective C is necessary because some of the MIDI programs will be Cocoa programs. To experiment with this approach, Ive written
a C++ wrapper for CFPropertyList integers, doubles, strings, and arrays. The Python that came installed in OS X 10.4 is version 2.3 and its
distutils does not support the
swig_opts setting. Therefore to build this C++ wrapper, you must say
swig -c++ -python cc_plist.i, then
python setup.py build.
A sample interaction shows how
CFPropertyList objects can be constructed and displayed in the Python interpreter. Note that without writing additional Python code, it can be quite clumsy to specify
CFPropertyList objects. For example, instead of saying
[1, 99.99, 'abc'], as one can achieve with
typemaps, one must say something like
plist([plist(1), plist(99.99), plist('abc')]). Another problem arises from another of SWIGs limitations: it does not support all target languages equally well! For example,
std_vector, which is used for CoreFoundation arrays in this C++ wrapper, is not supported for Chicken wrappers.
So you can tell Im more inclined to use the C/typemap approach after this study. Of course the disadvantage there is that a separate set of typemaps need to be written whenever a new target language is to be supported for the library. I suppose you cant have it both ways.
Lets Do the Same for Chicken
Thursday September 29, 2005
Now were really having some fun. I wrote
a few SWIG typemaps that will enable SWIG-wrapped functions with CFPropertyListRef parameters and results to be accessed from Chicken.
Chicken is of course a nice Scheme compiler with the BSD license. It doesnt matter very much for a compiler anyway because one will only be distributing compiled code in a commercial product. But compare this to
Guile which isnt a compiler and the CVS version of which uses the LGPL
last time I checked.
These typemaps were harder to write than the Python ones. One reason was that theres not a lot of information on the C interface to Chicken, especially regarding allocating return values on the heap. I also did some experiments on wrapping CFPropertyListRef objects with SWIG and C++ which Ill post soon.
A sample interaction shows calls to wrapped functions in the Chicken Scheme interpreter. Note that CoreFoundation arrays and dictionaries are represented by Scheme vectors and association lists, respectively.
SWIG Typemaps for CFPropertyListRef!
Tuesday September 27, 2005
Now were having a bit more fun. I wrote
a sample program today containing a few SWIG typemaps for wrapping CFPropertyListRef parameters and results. With them, Python objects of types String, Int, Float, Sequence, and Dict can now be passed into and out of functions written in C/CoreFoundation as CoreFoundation property lists. Herere a few such functions from the sample code.
extern void show(CFPropertyListRef p);
extern CFPropertyListRef noop(CFPropertyListRef p);
extern CFPropertyListRef xml(CFPropertyListRef p);
The function
show calls
CFShow to print a description of the input property list. The function
noop passes the input argument straight through to the result. It demonstrates that the conversions in both directions are correctly performed. The function
xml calls the CoreFoundation function
CFPropertyListCreateXMLData to create an XML representation of the input property list and returns a string in that representation.
Heres
a sample interaction that shows calls to these wrapped functions in the Python interpreter.
SWIG Typemaps for CFString
Monday September 26, 2005
I want to write a library that will completely change how MIDI programs are written on OS X. At the outset the use of
SWIG in its implementation is very appealing because wrappers for different languages can be generated, which means that the library can be called from Python, Scheme, Ocaml, Java, Perl, Tcl/Tk, etc. One must wonder why so few libraries are implemented this way.
I experimented with SWIG a little
a while ago. SWIG takes an interface specifications file and generates wrappers for functions in it so that these can be called from a target language. SWIG is capable of wrapping all C built-in types, arrays, structures, and pointers. For user-defined types, or to override its default behavior,
typemaps can be used to specify how values of these types are wrapped.
One problem I need to solve is to find a way to call my library from Objective C! Unfortunately a version back SWIG stopped supporting Objective C as a source language. Fortunately the CoreFoundation-Cocoa collection toll-free bridge allows this to happen with a bit of extra work (as Ill explain more clearly in a future entry). So Ive written
some sample code with a few typemaps for
CFString. To run it, you need to have SWIG 1.3.25 installed. To build the Python extension, issue the command:
python setup.py build
Then start Python:
PYTHONPATH=build/lib.darwin-8.2.0-Power_Macintosh-2.3/ python
changing your version numbers if necessary. The sample wraps the C function
CFStringRef uppercase(CFStringRef s);
defined in the file
example.c. Test it in the Python interpreter by typing:
import example
example.uppercase('SoME InPUt sTrING')