Pyllisp FFI Uses Generated JSON Headers
I got tired to scanning©/pasting through C header files for some while ago. It's stupid waste of time, and your usual C header got hundreds of messily formatted declarations.
Pyllisp FFI has a function ffi.library
, when you pass it just the path to the library it opens the library. Let's look into the interactive console of my latest pyllisp interpreter. The pyl>
denotes an input with output below:
pyl> lib = (ffi.library "libSDL2.so")
<library>
It finds the libSDL2.so and dlopens it. Though it's quite useless. You don't have any type annotations, and pyllisp doesn't attempt to guess them.
pyl> lib.SDL_Init
<handle SDL_Init from libSDL2.so>
pyl> (lib.SDL_Init 0)
Traceback:
shell: 1:0 1:16
Error: cannot call null
pyl>
pyl> lib.SDL_INIT_EVERYTHING
Traceback:
shell: 1:0 1:23
Error: Not in the library: SDL_INIT_EVERYTHING
If you'd like to use this library, you have to annotate the handles. In Pyllisp FFI you could do it like this:
pyl> Init = (ffi.cast lib.SDL_Init (ffi.cfunc ffi.int [ffi.int]))
<handle SDL_Init from libSDL2.so>
pyl> (Init 0)
0
ffi.library
has a feature to annotate the library right when you create it, check this out:
pyl> names = (dict)
<dict>
pyl> names['bob'] = 5
5
pyl> lib = (ffi.library "libSDL2.so" names)
<library>
pyl> lib.bob
5
Quite boring huh? Aside passing in constants, you may supply into the dictionary that the name wraps something:
pyl> names['Init'] = (ffi.wrap "SDL_Init" (ffi.cfunc ffi.int [ffi.int]))
<wrap SDL_Init <cfunc <signed 4> <signed 4>>>
pyl> lib.Init
<handle Init from libSDL2.so>
pyl> (Init 0)
0
Why have such feature in the FFI? It's there because in pyllisp, you're not supposed to annotate functions yourself. There's api.open
. Say you call (api.open "libSDL2.so")
, the following happens:
- Pyllisp searches for
libSDL2.json
and decodes it. - It is wrapped into a type resolver object. That object builds up type annotations when requested.
- Pyllisp calls for
ffi.open
for you, with the type resolver.
Here's an example of using the api.open
:
pyl> sdl = (api.open "libSDL2.so")
<library>
pyl> (sdl.WasInit sdl.INIT_EVERYTHING)
0
pyl> (sdl.Init sdl.INIT_EVERYTHING)
0
pyl> (sdl.WasInit sdl.INIT_EVERYTHING)
29233
pyl> sdl.INIT_EVERYTHING
29233
pyl>
So where to get those .json
-files from and how do they look like? I wrote a tool to generate them from C headers, in python. The libSDL2.json sits in the repository too. Theoretically any language could use the same header files, as they follow the naming conventions set by the library and are minimally mangled. Just to get rid of namespace prefixes and redundant type annotations that are mandatory on C.
The tool isn't complete, I still have to try the bindings out and fix possible minor bugs there are in the generation. Otherwise it should simplify use of the C libraries.