Table of Contents

Compiling Matlab mex files with GNU autotools

This page gives an introduction into using GNU autotools autoconf and automake to automate the building of MEX files.

There are several benefits to using the autotools. As projects grow bigger the Makefiles can become very complex. The source for the example setup can be found here.

configure.ac

Key autoconf macros:


In addition to the built in autoconf macros, your may write your own. In the config directory of the example is an m4 macro file matlab.m4. This macro checks for matlab given the argument --with-matlab=DIR. This will test if the link libraries and include directories exist, and make an import library for linking against the libmex.dll,libmx.dll, and libmat.dll. Once these are created once, the m4 should not make them again because it tests for their existance.

Makefile.am

Key automake variables:

Personal use: Generally I write many routines and make libraries out of them. This has the benefit of being able to reuse the code at a later point very easily by linking against the library. Typically, my mex sources have very little code in them; basically enough to take inputs from matlab, do some error checking, pass this on to library routines, then give the data back to matlab. Having given my opinion on using libraries, I should give a little introduction to making libraries with automake.
There are two ways to build libraries the older but still used way of using ar and ranlib, and the relatively newer libtool way. I think the older way is easier and it's what I use.
Building libraries with automake.

Building the example

Download the example. I will assume it is in /home/USER, so replace this with the actual path to where you have downloaded it.

    $ cd /home/USER
    $ unzip example.zip
    $ mkdir gnumex-autotools-build
    $ cd gnumex-autotools-build
    $ ../gnumex-autotools/configure --with-matlab=/cygdrive/c/matlab704
    $ make


You should now have dll/mexglx files in /home/USER/gnumex-autotools-build/refbook. You can enable compiling the fortran sources by passing --enable-fortran or --enable-fortran=yes. To disable building from the C sources, pass --disable-c or --enable-c=no, but you must enable fortran or configure will tell you that you must use either C or fortran.

Advanced Topics

Once you get used to using autotools, I hope you find them as useful as I do. Below are some topics I have come across I find invaluable.

Wrapping Functions

I have noticed that in many functions(primarily on windows) I use that get run a lot that I have trouble allocating memory. I speculate this is because as data starts to fill up matlab's heap space my call to the system level malloc "fails". I quoted fails because it's not that the system is out of memory, but matlab's heap space is. When this happens in matlab, they probably ask the OS to increase the heap space available and retry the alloc. Using plain malloc, calloc, realloc it fails and I don't want to tie my "platform independent" code to petitioning the OS for more memory. This was a prime concern for me because the point of my C code is to write both stand-alone code and matlab interfaces to that code, so I can't use Matlab's mxMalloc,etc without needing matlab. So we seem to be in a predicament.

So what's the solution?
The GNU linker ld has an option named --wrap symbol. This wraps all occurrences of symbol to __wrap_symbol.

How does this help?
Well all calls to wrapped symbols get passed to __wrap_symbol, even code that's not yours and has been compiled to say a library(i.e. you don't have the source). So what I do is when compiling mex functions I link it against a library that has the wrapped symbols defined in them and specify the --wrap options. This way when compiling the code for standalone I don't have to change the code AT ALL. And since the mex sources and my library sources are in different build trees I don't have to change the mex source either.

So how do you write a wrap function?
Here is the code for my wrapped malloc function.
void * __wrap_malloc(size_t size)
{
void *ptr;
ptr = mxMalloc(size);
if ( ptr != NUL )
mexMakeMemoryPersistent(ptr);
return ptr;
}

So, why did I make the memory persistent? Well one drawback to this method I learned the hard way is that Matlab must have some initialization code prior to the start of the mexFunction entry point that is being wrapped through this malloc too. Since by default matlab cleans up all memory from the mex function unless it's made persistent, it destroys this memory too, which it thinks is still there later and you end up corrupting memory. Is it a big deal to make all memory persistent. Not really. I haven't noticed any performance change. What it does mean is you still need to be a GOOD C programmer and clean up after yourself or you'll leak memory. This leak isn't permanent and would be freed when Matlab quits.

Allocating Memory

Since most of my code is written to be external to matlab, I frequently return pointer to allocated memory. If this is data that I want to pass back to matlab, This means I would double the memory and waste time copying memory from my pointer to the one matlab automaticaly allocates. Well, the copying time can be fixed by freeing the data pointer and setting it to the allocated one, but this still doesn't fix the memory useage.

Have you ever allocated an mxArray with all dimensions of 0? What happens is matlab still creates the mxArray, but doesn't allocate the data pointers because it doesn't know the size. Well, we can fix that by using mxSetDimensions. But how does that help? From the documentation it DOES NOT reallocate space for the pr/pi arrays. So we can use mxSetData and mxSetImagData to set it to point to our allocated space. This avoids both the time in copying and memory usage.

References


Many thanks to:

Ton Van Overbeek, who wrote the original scripts and .bat files and to:
Mark Levedahl
Lars Gregersen
Christian Merkwirth
and to:
Mumit Khan, for helpful discussion, and his contributions to gcc, mingw, dllwrap, which made the whole thing work.

Christopher Hulbert
11 August 2005
SourceForge.net Logo