I have had multiple occasions where I needed to quickly generate bindings to an existing C library. The repetitive nature of creating these bindings calls out for a tool to automate this tool. For this purpose, I have written a class, MG_DLM, that allows:

  1. creating wrapper binding for routines from a header prototype declaration (with some limitations from standard C)
  2. creating routines which access variables and pound defines
  3. allow adding custom routines written by the developer

I have used MG_DLM to create bindings for the GNU Scientific Library (GSL), CULA, MAGMA, and even IDL itself.

Define the routines

For our example, let’s make some basic random number generation routines from GSL available. The relevant routines from the gsl_rng.h header file that we would like to access from IDL are:

const gsl_rng_type *gsl_rng_env_setup(void);
gsl_rng *gsl_rng_alloc(const gsl_rng_type *T);
INLINE_DECL double gsl_rng_uniform(const gsl_rng *r);

We need to write a modified header file that MG_DLM will be able to understand. Since the pointers to gsl_rng_type and gsl_rng are returned by one routine and passed into another, we can just define them as IDL_PTRINT. For example, GSL_RNG_ALLOC will just return a 64-bit integer that represents a pointer to a gsl_rng. This integer can then be passed to GSL_RNG_UNIFORM. Our header will be:

void gsl_rng_env_setup();
IDL_PTRINT gsl_rng_alloc(IDL_PTRINT t);
double gsl_rng_uniform(IDL_PTRINT r);

We place these definitions in mg_gsl_rng_bindings.h for use when we create the DLM object.

Create the DLM

Next, we use MG_DLM to define our DLM containing these bindings. First, create a DLM object with basic metadata:

dlm = mg_dlm(basename='mg_gsl', $
             prefix='MG_', $
             name='mg_gsl', $
             description='IDL bindings for GSL', $
             version='1.0', $
             source='Michael Galloy')

Next, tell the DLM where the include directory and library are:

dlm->addInclude, 'gsl/gsl_rng.h', $
                 header_directory='/usr/local/include/gsl'
dlm->addLibrary, 'libgsl.a', $
                 lib_directory='/usr/local/lib', $
                 /static

dlm->addRoutinesFromHeaderFile, 'mg_gsl_rng_bindings.h'

For our example, we will also need to access the gsl_rng_default variable in the GSL library. In gsl_rng.h, it is declared as:

GSL_VAR const gsl_rng_type *gsl_rng_default;

To add a routine that accesses this variable, we just do:

dlm->addVariableAccessor, 'gsl_rng_default', type=14L

Finally, tell the DLM to write itself, both the .c and .dlm files, and then build itself:

dlm->write
dlm->build

We are now ready to use our DLM.

Example of using

We can now use our routines to generate random numbers from IDL:

n = 1000L
mg_gsl_rng_env_setup
t = mg_gsl_rng_default()
r = mg_gsl_rng_alloc(t)
u = dblarr(n)
for i = 0L, n - 1L do u[i] = mg_gsl_rng_uniform

Get the code for creating bindings (and a slightly more fleshed out set of GSL bindings) from the mglib repo.