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:
- AC_INIT
Initializes configure, processes arguments, and performs a few cheks.
All configure scripts must call this. This is one of only two
required macros.
- AC_OUTPUT
Tells configure to create the output files. This is the second
required macro.
- AC_CONFIG_FILES
Tells configure which files to create output. The argument should
be a space separated list of files (i.e. Makefile, etc).
- AC_PROG_CC
Tries to find a C compiler. If no input argument is given, it will
look for gcc and then cc. You can specify a space-separated list of
compilers to look for. In either invocation, configure first checks
for the CC environment variable and uses that definition if possible.
This way a user can use their own c compiler.
- AC_PROG_F77,AC_PROG_FC
Tries to find a Fortran 77 or 95/90/77 compiler respectively. Like
AC_PROG_CC, AC_PROG_F* can take an optional first argument specifying
a space-separated list of compilers to look for.
In either invocation, configure first checks for the F77/FC
environment variable and uses that definition if possible.
This way a user can use their own fortran compiler.
- AC_ARG_WITH(package,,,),AC_ARG_ENABLE(feature,,,)
Checks for an argument of the form --with-package and
--with-feature. Combine this with AC_SUBST to enable parts of the
build process or substitute variables.
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:
- bin_PROGRAMS
Ordinarily, this is used to specify the names of executable programs
that are to be built. But to date, this is the best way I can find
to trick automake into making shared libraries. Anyways, this
should be set to a space separated list of mex files (without the
extension).
- mexfile_SOURCES
First "mexfile" should be replaced by the name (exactly) of the mex
function in the bin_PROGRAMS list. This specifies all the source
files that are needed to make the mex function. No object files or
libraries go here, only sources. Note that you can mix languages on
this list too. So if your mex function uses both a C and fortran
source, both can be specified here.
- mexfile_CFLAGS,mexfile_FCFLAGS,mexfile_F77FLAGS,mexfile_CXXFLAGS
This is a space seperated list of flags to be passed to the C,
fortran, fortran 77, C++ compilers respectively. These typically
include include directories, optimization flags, etc.
- mexfile_LDFLAGS
This is a space separated list of flags mainly used during linking.
Flags such as library include directories (i.e. -L).
- mexfile_LDADD
This is a list of libraries the mex function needs to link against,
such as -lmex -lmx -lmat.
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.
- lib_LIBRARIES
This is equivelant to the bin_PROGRAMS mentioned earlier. This is
a list of libraries to make. Generally on *nix platforms the
convention is libname.a where "name" is replaced by whatever you
want to call your library.
- include_HEADERS
This is a space separated list of headers that should be
distributed with your library
- libname_a_SOURCES
This is equivelent to the mexfile_SOURCES mentioned earlier.
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.
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.
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