posted Tue 29 Jul 2014 by Michael Galloy under IDL
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.
[GNU Scientific Library]: http://www.gnu.org/software/gsl/ "GSL - GNU Scientific Library"
[CULA]: http://www.culatools.com "CULA"
[MAGMA]: http://icl.cs.utk.edu/magma/ "MAGMA"
#### 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:
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', $
description='IDL bindings for GSL', $
Next, tell the DLM where the include directory and library are:
dlm->addInclude, 'gsl/gsl_rng.h', $
dlm->addLibrary, 'libgsl.a', $
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:
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
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(r)
Get the code for creating bindings (and a slightly more fleshed out set of GSL bindings) from the [mglib repo].
[mglib repo]: https://github.com/mgalloy/mglib "mgalloy/mglib"