The Programs of the Week the Winter Returned
This Week’s Program: Mar 6 - Mar 10
It’s snowing in New York City right now. March is a month that always seems deceptive.
Last week I hit a bit of a wall with Racket’s GObject Introspection library. GIR is used to construct a language binding to a C library that uses GObject conventions. It’s really handy for my explorations with GStreamer. The problem with the Racket GIR library seems to be that when using objects, methods don’t inherit from parent classes and method return types aren’t transformed into useful representations (or they’re the wrong representation).
The last commit on the gir
library was an update to the README
in
April of 2016. Before that the previous commit was in July of 2015. An
open pull request to the docs has been open since March of 2016. I
think it’s fair to say that the project has been abandoned. So this
week I started a spike on my own GObject Introspection library within
overscan
.
7e846551e4f09b86b9bad807b555e7208709c675
The first thing I do is create a new file:
ffi/introspection.rkt
. What will likely happen is that I’ll move
this under ffi/unsafe/introspection
but I’m still trying to get a
feel for Racket collections and modules. We build up
our GIR library by first creating a FFI to libgirepository
, which is
a C library for working with GObject Introspection Repositories and
Typelibs.
0329371c278d80e2f23d8349a36c4402e41ce7bb
In addition to trying to understand how to use the GIRepository stuff, I’m also getting a better sense of using Racket and using Racket’s FFI. Specifically how to create Racket definitions of C types.
(introspect namespace)
returns a lambda that will then lookup a name
in that namespace.
5e8a914a44240a26a189138c8a42fa5e7d28219b
I make sure in my Emacs configuration that typing lambda “prettifies” to a λ character in Racket mode. Racket mode has a special “unicode-input-method” that allows you to replace other mathematical notation with unicode equivalents, but I found that kind of intrusive.
This is all just to get me more productive in Racket from within Emacs, where I can work on my code alongside a REPL.
f92f0efa7b3e0c78b2ca13fcaf6634520d2e5f80
Here, I look at a GIR namespace and construct a list of pairs of type and name for every name in the repository.
Now I can look and see everything that the Gst
(GStreamer)
repository contains. I can even do this for the GIRepository
namespace itself.
e8776c92d9ed42ec752951b2007ff88fa0a4dac8
Here, I deal with the GError
type. In C, a function
that takes a GError**
argument will set that pointer with an error
and that can be used as an exception message when that function enters
an error state. ffi/unsafe
allows me to capture this pointer value
and if the function returns a false or null pointer, I can raise an
exception in the Racket process. This is a pattern I’ll probably have
to get more comfortable with.
9c10e00b0b2ac687048ec1bf0975582d3fcaf548
Here I adjust my function
to case
on the type
of the info I get back from GIR from a particular name. I start with a
function
type. A
GIFunctionInfo
type
represents a function that could be called. To get the most out of
this type you also have to work with GICallableInfo
, GIArgInfo
,
and GITypeInfo
types.
The first step here is to get an understanding of all of the arguments and types that the function expects, and what the function’s return type is.
80059c66e25cc04521a0173e7d67059347957209
After some renaming and some more function calls, we’re left with an API that will look up a function based on a name, and then print out a string that represents the args that it needs and the type it returns:
> ((introspection "Gst") "version_string")
"fun () -> 'GI_TYPE_TAG_UTF8"
> ((introspection "Gst") "init_check")
"fun ('GI_TYPE_TAG_INT32 argc 'GI_TYPE_TAG_ARRAY argv) -> 'GI_TYPE_TAG_BOOLEAN"
> ((introspection "GIRepository") "type_info_get_tag")
"fun ('GI_TYPE_TAG_INTERFACE info) -> 'GI_TYPE_TAG_INTERFACE"
Cool! The next step is to actually construct a lambda that transforms
its arguments into the right C types to invoke
this C function.
I’m still working through what the API of my GIR module should be, then it’ll be about learning enough Racket to be able to shape and implement that API.
So much to learn!
– Mark