Wrap a C library with Ruby

This article explains how C functions can be used from within Ruby. There are two ways: the new way is to use a foreign function interface and the old way is to write a Ruby extension.

To make the example real, it will add Ruby spport for the AFsplitter library used by LUKS.

Prepare the shared library

Begin by downloading C library:

$ curl http://clemens.endorphin.org/AFsplitter-0.1.tar.bz2 | tar jxvf -

It's Makefile statically links a test program. I modified this to provide a shared library:

CFLAGS+= -fPIC
TEST=af-test
LIB=libafsplit.so
LIBOBJ=af.o sha1.o XORblock.o random.o

$(TEST): $(TEST).o $(LIB)
    $(CC) $^ -o $@ $(LIB)

$(LIB): $(LIBOBJ)
    $(CC) $^ -o $@ -shared

clean:
    rm -f $(OBJ) $(LIBOBJ) $(LIB) $(TEST)

Then, I confirmed that I could built and run the test:

$ make
$ LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH" ./af-test
Data equal, should be equal
Data not equal, should be not equal

The following sections will make it possible to use the shared library, libafsplit.so, from Ruby.

FFI

Ruby-FFI, the Ruby foreign function interface lets us write Ruby code that uses functions in a C library.

Create a gem

$ bundle gem afsplitter

copy afsplitter.so to lib

add dependency for ffi into gemspec; complete documentation entries in gemspec.

write lib/afsplitter.rb

write test/test_afsplitter.rb

build with rake build

test with rake

commit to repo

set up remote (i.e github or gitolite) and push

release gem with rake release

Extensions

http://media.pragprog.com/titles/ruby3/ext_ruby.pdf

This article explains a way to make Ruby bindings for an existing C library. In particular, using SWIG to make a wrapper for the AFsplitter library used by LUKS.

Install required packages:

$ sudo pacman -S swig

Create a gem

$ bundle gem afsplitter 
$ cd afsplitter

Download and build the C library sources:

$ curl http://clemens.endorphin.org/AFsplitter-0.1.tar.bz2 | tar jxvf -
$ cd AFsplitter-0.1

Write a SWIG input file, afsplitter.i:

%module afsplitter
%{
    #include "af.h"
%}

append the function prototypes

$ sed -n -r 's/^(int AF_.*;)/extern \1/p' af.h >> afsplitter.i

Generate wrapper:

$ swig -ruby -autorename afsplitter.i

Write extconf.rb that builds a Makefile:

$ echo -e "require 'mkmf'\ncreate_makefile('afsplitter')" > extconf.rb

Save existing Makefile and make new one

Create a gem

$ bundle gem afsplitter 

Create a SWIG interface file

More gem stuff

also hoe, jeweler, bundler and ore.