Compiling and linking MATLAB MEX files

In this post, I assume that you are already familiar with compiling and linking C code, have MATLAB installed, and are using gcc on Linux (the process is very similar on MacOS - MacOS-specific notes are at the end). Please note that I have no affiliation with MathWorks/MATLAB, I'm just writing from the perspective of someone who's used MATLAB.

MATLAB can interact with custom C and C++ code. To do so, you need to write code that makes use of MATLAB-specific C/C++ functions and objects and includes a particular "gateway function", essentially defining the entry point to your code that MATLAB should use. Then, once you've written your source code, you compile and link it into a shared library while including MATLAB-specific header files, and linking against MATLAB-specific libraries. You also need to give the shared library a special file extension, e.g. "mexa64" on Linux (instead of the regular shared library/object file extension ".so"). With this, you've created what MathWorks refer to as a MEX file.

When I learned about this process, I couldn't find a straightforward guide that would explain it. Much of the information from MathWorks themselves suggests and/or assumes that you use the MATLAB mex command to compile and link your source code. The tool provides some convenience, especially when producing MEX files manually, but it can be a bit unwieldy if you want to automate the compilation and linking process. In addition to this, setting up the compilation and linking helps to understand what's really happening, in my opinion.

So, let's look at how to create a MEX file.

C source code

When it comes to actually writing the C code, MathWorks do have a clear and introductory article. Rather than trying to rephrase what they say, I recommend you check out the article.

For this post, we'll use even simpler code than what MathWorks suggest, saved in "hello.c":

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
  mexPrintf("Hello, MEXico!\n");
}

As detailed in the MathWorks article, the mexFunction serves as a gateway function to your C code, and it must have exactly the signature used here. For information on how to do something more interesting than just printing a message, again, please read the MathWorks article.

MATLAB header and library files

On this MATLAB documentation page, under "C MEX Functions", you can see what header and library files are required for compiling and linking C code into MEX files. On Linux, the library files are located in "matlabroot/bin/glnxa64" (e.g. "/usr/local/MATLAB/R2022a/bin/glnxa64/") while the header files are located in "matlabroot/extern/include" (e.g. "/usr/local/MATLAB/R2022a/extern/include/"). The library files we need are "libmex.so" and "libmx.so" ("libmat.so" is also frequently required, but we can skip it since our C code is so simple).

Compiling and linking

With our source code in place, and knowing where the header and library files are located, we're ready to compile.

gcc -I<matlabroot>/extern/include -shared -L<matlabroot>/bin/glnxa64 -lmex -lmx hello.c -o hello.mexa64
# e.g. gcc -I/usr/local/MATLAB/R2022a/extern/include -shared -L/usr/local/MATLAB/R2022a/bin/glnxa64 -lmex -lmx hello.c -o hello.mexa64

This should result in a "hello.mexa64" file. If not, double check the flags and paths you specified.

Calling our function from MATLAB

Now boot up MATLAB and make sure that the directory with your "hello.mexa64" file is on MATLAB's path, most easily done by browsing to the directory in MATLAB. Then, in the MATLAB prompt, simply run:

hello()

You should see the friendly greeting that we wrote in C.

So that's it! You've now produced your own MEX file.

What to do on MacOS

If you're on MacOS, you can follow essentially the same steps as outlined above. You just need to make sure to update the MATLAB header/library directory paths (note that the library directory is architecture-specific) and change what file extension you use for your MEX file, as mentioned on the MATLAB mexext documentation page. If you have an Intel (x86_64 architecture) Mac, you need ".mexmaci64". If you have an Apple Silicon (ARM64) Mac, it's ".mexmaca64". So for instance, this should work on an Apple Silicon Mac:

clang -I<matlabroot>/extern/include -shared -L<matlabroot>/bin/maca64 -lmex -lmx -o hello.mexmaca64
# e.g. clang -I/Applications/MATLAB_R2021b.app/extern/include -shared -L/Applications/MATLAB_R2021b.app/bin/maca64 -lmex -lmx -o hello.mexmaca64 

Links