This is a personal blog. The opinions expressed here represent my own and not those of any of my employers or customers.

Except if stated otherwise, all the code shared is reusable under a MIT/X11 licence. If a picture is missing a copyright notice, it's probably because I'm owning it.

Thursday, March 28, 2013

Producing Better Bindings: Completeness

Note: like the previous post, this one is a follow-up on a series written by someone else. We're all building on top of giant's shoulders. My giant today is S├ębastien Pouliot from Xamarin. Read his series Producing Better Bindings.

Second Note: if you're reading this from a news aggregator, you might miss the embedded gists. Read the original there.

I'm lately enjoying writing bindings for Xamarin.iOS and Xamarin.Mac, a lot for the fun, very little for profit. The biggest project by far was creating a managed bindings for cocos2d (v2). This library is huge (~2500 public methods), and the API is far from being fixed in stone. The library is so big that at some point I just gave up, until Miguel resumed the effort during end-of-year break.

No chocolate

One of my worst nightmare was that, at the point of completion, the API would probably outdated, and going through every .h at every release to check consistency looked very expensive from a maintenance point of view. Hopefully, S├ębastien came up with automated tests, removing a lot of the burden. There was still a missing part. making sure we were not missing any (important) part of the exposed API. In Producing Better Bindings #1, he said:
There’s no easy way to test for missing constructors[...]. That would require static analysis (not introspection) in order to be useful.
 It was very much like a "you can't get chocolate"-day for me. Which means a lot for a Belgian.

Static Analysis

I wanted that feature badly. But I wasn't in the mood of writing (another) .h parser, just to extract the public API (though I could have used the same tools used for generating documentation). So I opted for analysing the generated library, but not at runtime, just after compiling.

So I added a step in my Makefile that looks like this:
#static analysis
%.selectors: %.a
 nm -P $< | grep "^[-+]\[.*\] t" > $@

which generate a file containing entries like this:

+[CCLayerColor layerWithColor:] t b84 0
+[CCLayerColor layerWithColor:width:height:] t b1b 0
-[CCLayerColor blendFunc] t 1167 0
-[CCLayerColor changeHeight:] t ecc 0
-[CCLayerColor changeWidth:] t e87 0
-[CCLayerColor changeWidth:height:] t e4b 0
-[CCLayerColor draw] t fa1 0
-[CCLayerColor initWithColor:] t d81 0
-[CCLayerColor initWithColor:width:height:] t c3f 0
-[CCLayerColor init] t bd7 0
-[CCLayerColor setBlendFunc:] t 1182 0
-[CCLayerColor setColor:] t 10b9 0
-[CCLayerColor setContentSize:] t de2 0
-[CCLayerColor setOpacity:] t 1114 0
-[CCLayerColor updateColor] t f10 0

which is all we need (and some more we don't need).

The fixture

The fixture looks like all other Binding Test fixture. You set LogProgress and ContinueOnFailure to the value you want, you override the Assembly property, and you optionally Skip() some types.

Parsing the file

Parsing the generated file isn't part of the base fixture, as it's tied to how you extract the selectors; and you have to override Selectors (). But if you reuse the Make command, you can also reuse this parser:

Skipping categories

If the library you're binding uses categories, like cocos2d does, you can skip full categories:

What's missing ?

Very few actually. Maybe detecting is all the exposed Fields are bound in your C# API.

If you liked this post, you probably will also like other stuffs I'm doing. Contact me, I'm open for contracting.

No comments:

Post a Comment