|
|
# What are MATLAB MEX files?
|
|
|
|
|
|
MEX files are functions written in C or C++ that are callable in the
|
|
|
MATLAB scripting language in a MATLAB interpretor.
|
|
|
[MATLAB](http://www.mathworks.com/matlab) is a 'Matrix Laboratory', a
|
|
|
general purpose scientific scripting language owned by [The
|
|
|
MathWorks](http://www.mathworks.com) company.
|
|
|
|
|
|
Details of writing MEX files can be found in the [MATLAB
|
|
|
documentation](http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_external/bp_kqh7.html).
|
|
|
|
|
|
## Before you begin
|
|
|
|
|
|
MATLAB is a language with good syntax for working with matrices, a
|
|
|
variety of functions, excellent documentation, and it is ubiquitous
|
|
|
throughout the academic, scientific community. On the other hand, it is
|
|
|
extremely slow, has poor memory utilization, is prohibitively expensive,
|
|
|
sees little use outside academia, has a language syntax that is only
|
|
|
good for simple procedural scripting, is closed source, and has numerous
|
|
|
bugs. Writing MEX files is often an attempt to address some of these
|
|
|
limitations -- speed and memory usage. However, it is a difficult and
|
|
|
not very elegant solution. Instead, researchers should consider using
|
|
|
superior products, such as [SciPy](http://scipy.org),
|
|
|
[SciLab](http://www.scilab.org), [Sage](http://www.sagemath.org/), or
|
|
|
[Octave](http://www.gnu.org/software/octave/index.html).
|
|
|
|
|
|
# Why would you want to use CMake for creating MEX files?
|
|
|
|
|
|
If you have a very small project that consists of only a single source
|
|
|
code file that does not link to other libraries, then simply using the
|
|
|
MEX compiler at the command line is all that you need. However, if your
|
|
|
project is non-trivial, there are many advantages to using CMake. A make
|
|
|
system allows you to recompile and link *only* the files that change
|
|
|
during development and to perform parallel builds. CMake provides a
|
|
|
configuration system for finding libraries on systems. The are many
|
|
|
advantages to organizing and controlling the build system in a simple
|
|
|
and powerful way, which CMake can do, [among other
|
|
|
things](Really_Cool_CMake_Features "wikilink").
|
|
|
|
|
|
# How do you use CMake with MATLAB?
|
|
|
|
|
|
## Background on the MATLAB MEX "compiler"
|
|
|
|
|
|
MATLAB comes with a MEX "compiler". It is not a true compiler, but a
|
|
|
[frontend build
|
|
|
script](http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_external/f24338.html)
|
|
|
to the compiler of your choice. On MS Windows it is a perl script, and
|
|
|
on Unix-like systems it is a shell script, although they have the same
|
|
|
user interface. Issuing
|
|
|
|
|
|
mex -setup
|
|
|
|
|
|
allows you to setup the configuration file the mex script uses to
|
|
|
determine which compiler it will use, the flags it will pass, etc.
|
|
|
|
|
|
mex -v
|
|
|
|
|
|
shows the compiler and settings the build script is using.
|
|
|
|
|
|
The MEX compiler can process C, C++, or Fortran code. The code must
|
|
|
contain a gateway function with specific syntax that MATLAB hooks into.
|
|
|
Primary MATLAB itself is written is C, and a variety of functions are
|
|
|
available in the *mex.h* header for interrogating MATLAB data
|
|
|
structures, allocating memory in a way that it is controlled by MATLAB,
|
|
|
etc. The result of this process is a shared library (dll) *mexfile* that
|
|
|
is loaded by by the MATLAB interpretor when the basename is found in
|
|
|
MATLAB's path.
|
|
|
|
|
|
## How can CMake fit into this process?
|
|
|
|
|
|
There are three basic approaches to utilize CMake for the process of
|
|
|
generating
|
|
|
mexfiles.
|
|
|
|
|
|
### Try to emulate the logic built into the mex build script in CMakeLists.txt
|
|
|
|
|
|
Since mexfiles are simply native shared libraries with some special
|
|
|
functions, etc., it is possible to bypass the mex build script
|
|
|
completely. The logic built into the mex built script can be replaced by
|
|
|
appropriate scripting of the *CMakeLists.txt*.
|
|
|
|
|
|
Unfortunately, this approach requires significant effort, and it is
|
|
|
difficult to maintain. In addition to the mex gateway function, a MEX
|
|
|
file requires specific preprocessor definitions, compiler flags, link
|
|
|
scripts, linked libraries, etc. These must be reproduced in the
|
|
|
CMakeLists.txt. The options vary across compilers and across platforms.
|
|
|
Furthermore, MathWorks produces new MATLAB versions twice a year, and
|
|
|
these options change across versions. Configuration must be maintained
|
|
|
for every MATLAB version that is desired, and new releases of MATLAB
|
|
|
likely break the build process.
|
|
|
|
|
|
### Tell CMake to treat the mex build script as the project's compiler
|
|
|
|
|
|
The other option is to tell CMake to treat the mex build script as the
|
|
|
project's compiler. This approach dulls the power of CMake in some cases
|
|
|
due to the limited capabilities of the mex script, but it makes project
|
|
|
much more maintainable. This article describes this approach.
|
|
|
|
|
|
If the *mex* script is in the system's *PATH* environment variable,
|
|
|
setting the *CC* or *CXX* environmental variable is all that is
|
|
|
required:
|
|
|
|
|
|
CC=mex CXX=mex cmake /path/to/project/source
|
|
|
|
|
|
This method requires a patched version of CMake. The patch can be
|
|
|
obtained [here](http://public.kitware.com/Bug/view.php?id=9240).
|
|
|
|
|
|
There are some differences from normal CMake usage when using the mex
|
|
|
build script as the system compiler. Instead of configuring additional
|
|
|
compiler flags from within CMake, compiler flags for the underlying
|
|
|
compiler must be set in the mexopts configuration file. Compiler flags
|
|
|
configured in CMake should be [options sent to the mex
|
|
|
compiler](http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_external/f24338.html).
|
|
|
|
|
|
It is still possible to use the
|
|
|
|
|
|
include_directories()
|
|
|
link_directories()
|
|
|
target_link_libraries()
|
|
|
|
|
|
scripting directives in the project's CMakeLists.txt.
|
|
|
|
|
|
Since all mexfiles are shared libraries,
|
|
|
|
|
|
add_executable()
|
|
|
add_library(library_name STATIC sources.cpp)
|
|
|
|
|
|
are not valid ways for generating targets. CMake targets should be made
|
|
|
with
|
|
|
|
|
|
add_library(library_name SHARED sources.cpp)
|
|
|
|
|
|
or
|
|
|
|
|
|
add_library(library_name MODULE sources.cpp)
|
|
|
|
|
|
### Build your own static library using CMake, and then linking at the final stage
|
|
|
|
|
|
This is a fairly neat workaround for the poorness of MEX. In principle,
|
|
|
it allows the user to build an abitrary static library using the usual
|
|
|
build toolchain, and then only invoke the mex compiler at the final
|
|
|
stage, linking everything together into a MEX file. It sidesteps the
|
|
|
logical checks that MEX thinks it needs to carry out.
|
|
|
|
|
|
The method goes something like this: Replace your mexFunction() and
|
|
|
mexAtExit() and other routines that MATLAB would expect to find with
|
|
|
some placeholder. e.g. __mexFunction__() and __at_exit__().
|
|
|
|
|
|
Compile a static library using a suitably defined CMakeLists.txt that
|
|
|
uses the usual build tools, e.g. gcc.
|
|
|
|
|
|
Create a stub function that wraps your __mexFunction__() etc with
|
|
|
the MATLAB defined functions mexFunction() etc. I.e. it simply enters
|
|
|
the function and calls the alternative version. An example is
|
|
|
[Mex_stub.cpp](/uploads/6a1769e6300d0ee2cbac308e01e77809/Mex_stub.cpp).
|
|
|
|
|
|
Add the following to your CMakeLists.txt file:
|
|
|
|
|
|
ADD_CUSTOM_COMMAND(TARGET ${PROJECT_NAME}
|
|
|
POST_BUILD
|
|
|
COMMAND ./mex_link.sh ${PROJECT_NAME} ${MEX_SAVE_PATH}
|
|
|
)
|
|
|
|
|
|
This instructs CMake to call ./mex_link.sh when the static library has
|
|
|
been built.
|
|
|
|
|
|
mex_link.sh is a short script that compiles mex_stub.c (or cpp) and
|
|
|
then calls mex to link everything together. A suitable bash script would
|
|
|
be:
|
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
|
OUTPUT=$1
|
|
|
STATIC_LIB_NAME=$OUTPUT
|
|
|
MOVE_LOCATION=$2
|
|
|
LINKER_FLAGS=''
|
|
|
|
|
|
echo 'Running godawful mex linking hack...'
|
|
|
# mex_stub.o compiled with:
|
|
|
gcc-4.1 -g -Wall -fPIC -std=c99 -pthread -DMX_COMPAT_32 -DMATLAB_MEX_FILE \
|
|
|
-I/opt/matlab/latest/extern/include -c mex_stub.c -o mex_stub.o
|
|
|
mex -g -cxx CC='gcc-4.1' CXX='gcc-4.1' LD='gcc-4.1' -L./ -lpthread -lgthread-2.0 \
|
|
|
-lrt -lglib-2.0 -l$STATIC_LIB_NAME $LINKER_FLAGS -output $OUTPUT mex_stub.o
|
|
|
mv $OUTPUT.mexa64 $MOVE_LOCATION
|
|
|
|
|
|
The onus is on the user to get all the linker flags correct. Certainly,
|
|
|
"-lpthread -lgthread-2.0 -lrt -lglib-2.0" are all project dependent
|
|
|
flags included as an example.
|
|
|
|
|
|
MEX_SAVE_PATH will also need to be defined, often simply as:
|
|
|
|
|
|
SET(MEX_SAVE_PATH "${CMAKE_SOURCE_DIR}")
|
|
|
|
|
|
The result of the make should be a built MEX file that works fine with
|
|
|
MATLAB.
|
|
|
|
|
|
Notes: The following flags should be added as compile flags -fPIC
|
|
|
-DMX_COMPAT_32 -DMATLAB_MEX_FILE (the last 2 just being defines)
|
|
|
using (I can't remember if the -std=c99 is optional or
|
|
|
not):
|
|
|
|
|
|
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -std=c99 -DMX_COMPAT_32 -DMATLAB_MEX_FILE")
|
|
|
|
|
|
Adding something like the following to your CMakeLists.txt file will
|
|
|
cause make clean to work
|
|
|
properly:
|
|
|
|
|
|
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${MEX_SAVE_PATH}/${PROJECT_NAME}.mexa64;mex_stub.o")
|
|
|
|
|
|
This technique has only been tested with GCC under linux. Not sure if it
|
|
|
will work anywhere else.
|
|
|
|
|
|
# Hello World Example
|
|
|
|
|
|
The source code for a "hello world" project can be
|
|
|
[downloaded](http://github.com/thewtex/matlab-cmake-hello-world/downloads)
|
|
|
or
|
|
|
[examined](http://github.com/thewtex/matlab-cmake-hello-world/tree/master).
|
|
|
|
|
|
To compile this example, unpack the source, then
|
|
|
|
|
|
mkdir hello_b
|
|
|
cd hello_b
|
|
|
CC=/path/to/mex CXX=/path/to/mex /path/to/cmake /path/to/source
|
|
|
make
|
|
|
|
|
|
Next, at a MATLAB prompt,
|
|
|
|
|
|
cd /path/to/hello_b/tests/
|
|
|
hello
|
|
|
|
|
|
This project has successfully been tested on the following setups:
|
|
|
|
|
|
- 32-bit Linux/MATLAB R2007a/gcc-4.1.1
|
|
|
- 64-bit Linux/MATLAB R2007a/gcc-4.1.1
|
|
|
- 64-bit Linux/MATLAB R2009a/gcc-4.1.2
|
|
|
- 32-bit WindowsXP/MATLAB
|
|
|
R2008a/[gnumex](http://gnumex.sourceforge.net/)-MSYS-MinGW
|
|
|
- 32-bit WindowsXP/MATLAB
|
|
|
R2008a/[gnumex](http://gnumex.sourceforge.net/)-Cygwin-MinGW
|
|
|
|
|
|
# More complex example: ITK based image reader
|
|
|
|
|
|
[Here](http://github.com/thewtex/matlab-itk-import/tree/master) is a
|
|
|
more complex project that demonstrates finding external projects, adding
|
|
|
additional include directories, and linking to libraries.
|
|
|
|
|
|
This project creates an [ITK](http://www.itk.org) based image reader
|
|
|
that supports [all the image formats accessible to
|
|
|
ITK](ITK_File_Formats "wikilink").
|
|
|
|
|
|
# Platform specific issues
|
|
|
|
|
|
## Windows
|
|
|
|
|
|
The mex build script in Windows is set up to only look for static
|
|
|
libraries when linking, not dll's.
|
|
|
|
|
|
### Gnumex
|
|
|
|
|
|
[Gnumex](http://gnumex.sourceforge.net) is a utility designed to help
|
|
|
setup the mexopts.bat mex configuration file to use GNU tools on
|
|
|
Windows. Unfortunately, the mex build script does not look for static
|
|
|
libraries made with the GNU toolchains correctly. Apply the following
|
|
|
patch to ${MATLAB_ROOT}/bin/mex.pl so that the script can see those
|
|
|
libraries.
|
|
|
|
|
|
```
|
|
|
--- mex.pl.backup 2009-07-03 10:46:30.095025600 -0500
|
|
|
+++ mex.pl 2009-07-04 19:55:04.241083200 -0500
|
|
|
@@ -1103,6 +1103,7 @@
|
|
|
my $lib_found = 0;
|
|
|
foreach my $lib_dir (@IMPLICIT_LIB_DIRS) {
|
|
|
my $win_name = mexCatfile($lib_dir, $1 . ".lib");
|
|
|
+ my $mingwwin_name = mexCatfile($lib_dir, "lib" . $1 . ".a");
|
|
|
my $unx_name = mexCatfile($lib_dir, "lib" . $1 . ".lib");
|
|
|
if (-e $win_name) {
|
|
|
$IMPLICIT_LIBS .= " " . smart_quote($win_name);
|
|
|
@@ -1112,6 +1113,10 @@
|
|
|
$IMPLICIT_LIBS .= " " . smart_quote($unx_name);
|
|
|
$lib_found = 1;
|
|
|
last;
|
|
|
+ } elsif (-e $mingwwin_name) {
|
|
|
+ $IMPLICIT_LIBS .= " " . smart_quote($mingwwin_name);
|
|
|
+ $lib_found = 1;
|
|
|
+ last;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
### MSYS
|
|
|
|
|
|
In order to run the mex build script in
|
|
|
[MSYS](http://www.mingw.org/wiki/MSYS), a script such as the following
|
|
|
is required:
|
|
|
|
|
|
#!/bin/sh
|
|
|
MATLAB_DIR='/c/Program Files/MATLAB/R2008a'
|
|
|
"${MATLAB_DIR}/sys/perl/win32/bin/perl.exe" "${MATLAB_DIR}/bin/mex.pl" "$@"
|
|
|
|
|
|
Place it in a location such as */usr/local/bin/mex*.
|
|
|
|
|
|
Use the CMake Generator (-G switch to cmake.exe) *MSYS Makefiles*.
|
|
|
|
|
|
### Cygwin
|
|
|
|
|
|
In order to run the mex build script in
|
|
|
[Cygwin](http://www.cygwin.com/), a script such as the following is
|
|
|
required:
|
|
|
|
|
|
#!/bin/sh
|
|
|
MATLAB_DIR='C:\Program Files/MATLAB/R2008a'
|
|
|
"${MATLAB_DIR}/sys/perl/win32/bin/perl.exe" "${MATLAB_DIR}/bin/mex.pl" "$@"
|
|
|
|
|
|
Place it in a location such as */usr/local/bin/mex*
|
|
|
|
|
|
Use the make.exe found [here](http://www.cmake.org/files/cygwin/).
|
|
|
|
|
|
Use the CMake Generator (-G switch to cmake.exe) *Unix Makefiles*.
|
|
|
|
|
|
![Example](/uploads/ae7dc560ffbaf22928764201f1200ce1/Example.jpg)
|
|
|
|
|
|
----
|
|
|
This page was initially populated by conversion from its [original location](https://public.kitware.com/Wiki/CMake/MatlabMex) in another wiki. |