MexIFace
A C++/Matlab object-based interface library and cross-platform CMake MEX build tool.
MexIFace Documentation

MexIFace

A C++/Matlab object-based interface library and cross-platform CMake build system for creating interactive Matlab MEX modules with persistent state and complex behavior.

About

MexIFace diagram

The MexIFace class provides a flexible means of wrapping a complex C++ library into a Matlab class via Matlab's MEX function extension method. A standard Matlab MEX module implements a single function API, with no obvious way to manage shared state across one or more interacting MEX components. A MexIFace generated MEX module is wrapped in a regular Matlab handle class interface with normal Matlab properties and methods. MexIFace Matlab objects have associated C++ state that is persistent across method calls into the MEX module.

Instead of the procedural workflow implied by the static mexFunction() interface, a MexIFace wrapped class can be used interactively. Multiple objects of the wrapped type can be created and accessed independently using the same MEX module. Each instantiated object has its own persistent state; and when Matlab garbage collects a MexIFace object, it's C++ resources are freed as well.

Other important features:

Quick Start

Documentation

The MexIFace Doxygen documentation can be build with the OPT_DOC CMake option and is also available online:

Motivation

Matlab uses compiled plugins called MEX files to enable linking and running C and C++ code. A MEX file is a shared object file (ELF on Linux and DLL on Windows) that is dynamically loaded by the Matlab binary when the function it names is called. Each MEX file presents to Matlab an interface consisting of exactly one function with variable input and output arguments.

1 function varargout = mexFunction(varargin)

Separate MEX functions have no direct way to communicate with this API, and as C and C++ libraries become more complex this isolated, static function interface becomes increasingly restrictive.

Complex simulations an analysis libraries have more demanding requirements; they must:

In other words, complex libraries are much more like objects than functions. An object-oriented MEX file interface provides an easier, safer, faster, and more organized way of interacting with complex C++ libraries from Matlab.

Armadillo and mxArrays

MexIFace uses the Armadillo package to provide an efficient and powerful C++ interface to Matlab array types. Passing and returning large array data between C++ and Matlab can be very inefficient if data needs to be copied repeatedly. The Armadillo auxillary-memory constructors allow C++ Armadillo arrays to transparently manipulate Matlab mxArray raw data, as both use column-major layouts.

This allows the same memory allocated by Matlab to be used in C++ with very little overhead incurred when passing large array arguments. Return arguments can also be allocated from C++ into Matlab managed memory using Matlab's mxArray API, then mapped directly to an Armadillo C++ array used as output.

The mexiface::MexIFace class implements templated methods to succinctly convert data views between mxArray and armadillo array data types,

mxArray *matlab_vec, *matlab_mat, *matlab_cube;
...
//Interpreting matlab arrays as armadillo arrays
arma::vec cxx_vec = getVec(matlab_vec);
arma::mat cxx_mat = getMat(matlab_mat);
arma::cube cxx_cube = getCube(matlab_cube);
//Writing armadillo arrays to new matlab mxArrays
mxArray *out_vec = toMXArray(cxx_vec)
mxArray *out_mat = toMXArray(cxx_mat)
mxArray *out_cube = toMXArray(cxx_cube)
//Creating an output matlab array buffer to write into
//Each armadillo array points to matlab mxArray memory
arma::vec buf_vec = makeOutputArray(nelem);
arma::mat buf_mat = makeOutputArray(nrows,ncols);
arma::cube buf_cube = makeOutputArray(nrows,ncols,nslices);

Building and Installing

MexIFace uses the MATLAB_ROOT and MATLAB_ROOTS environment variables to find Matlab installations. For each Matlab release found, the build system creates a CMakeMexIFace::MexIFaceX_Y target corresponding to a libMexIFaceX_Y.so library, where X_Y is the numerical release code for each Matlab as returned by Matlab version command. Each Matlab release has potentially incompatible dependency and linking requirements, so a MexIFace library must be produced for each Matlab release that will be targeted.

Quick scripts

1 export MATLAB_ROOTS=/opt/matlab:$HOME/opt/matlab:...

Native Linux build

1 ./scripts/build.sh
2 export MATLABPATH=$(pwd)/_install/lib/MexIFace/matlab:$MATLABPATH

Matlab glnxa64 R2016b+: Linux gcc-4.9.4 environment cross-compile.

1 export X86_64_GCC4_9_LINUX_GNU_ROOT=...
2 ./scripts/build.gcc4_9.sh
3 export MATLABPATH=$(pwd)/_gcc4_9.install/lib/MexIFace/matlab:$MATLABPATH

Matlab glnxa64 R2018a+: Linux gcc-6.5.0 environment cross-compile.

1 export X86_64_GCC6_5_LINUX_GNU_ROOT=...
2 ./scripts/build.gcc6_5.sh
3 export MATLABPATH=$(pwd)/_gcc6_5.install/lib/MexIFace/matlab:$MATLABPATH

Matlab win64 R2016b+: Windows MXE-MexIFace mingw-w64/gcc-4.9.4 environment cross-compile

1 export MXE_ROOT=...
2 ./scripts/build.wim64.sh
3 export MATLABPATH=$(pwd)/_win64.install/lib/MexIFace/matlab:$MATLABPATH

Run Matlab unit tests on command line

1 matlab -nodesktop -r "startupMexIFace();run(MexIFace.Test.TestMexIFace)"

Setup MexIFace paths from inside matlab

1 cd('install_dir/lib/MexIFace/matlab')
2 startupMexIFace()
3 results = run(MexIFace.Test.TestMexIFace)

Core Dependencies

Matlab and GCC Compatibility

In order to build for a particular Matlab target environment, the development machine must have system libraries and all relevant dependencies built with the correct version of GCC.

For C++, the most important restriction involves libsdtc++ versioning, which prevents the use of a GCC with a CXXABI version newer than that used by the Matlab release targeted. Currently the following GCC versions are supported for use with MexIFace.

GCC Version Compatible Matlab Releases
gcc-4.9.4 R2016b+
gcc-6.5.0 R2018a+

BLAS and LAPACK

The BLAS and LAPACK libraries are common numerical dependencies. Matlab includes internal BLAS and LAPACK libraries that used 64-bit integers for array indexing. Many commonly available BLAS and LAPACK implementations instead use an incompatible 32-bit integer ABI. To make dual-use C++ and Matlab libraries it necessary to have system versions of the 64-bit BLAS and LAPACK.

CMake general Variables and Options

Other Dependencies

Git subrepo modules

These dependencies are included via the git subrepo mechanism, unlike git submodule there is not need to fetch subrepos in a seperate step after cloning.

External Projects

These packages are specialized CMake projects. If they are not currently installed on the development machines we use the AddExternalDependency.cmake module which will automatically download, configure, build and install the CMake-based dependency to the CMAKE_INSTALL_PREFIX. The dependency can then be found through the normal CMake find_package() system.

Getting a linkable Matlab stub environment

Because Matlab is closed-source we cannot provide the actual Matlab libraries necessary to link the MexIFace library. If you do have one or more valid releases of Matlab, and you would like to build or test build in an environment with no valid Matlab license, you can use what we call a linkable-stub Matlab environment. The result is archives matlab_stub-ARCH-VERS.tar.bz2 for each find-able <atlab root under the given search paths:

> ./scripts/create-matlab-linker-stub.py –outdir <outdir> <matlab_root_search_paths...>

LICENSE