How to Use MEX API Compatibility for Porting MATLAB Code to Nelson

Nelson provides a MEX C API Compatibility layer that allows you to compile and run existing MATLAB MEX-files without modifying the C/C++ source code.

The nelson-lang/nelson repository implements a complete MEX API compatibility system that mirrors MATLAB's mex.h, matrix.h, and engine.h headers. This compatibility layer enables seamless porting of MATLAB extensions by providing identical function signatures, memory management routines, and runtime behaviors.

Understanding the MEX API Compatibility Architecture

The compatibility layer consists of several interconnected components that replicate MATLAB's MEX environment.

Header Compatibility Layer

The core headers declare the same structs, types, and functions that MATLAB code expects. In modules/mex/src/include/mex.h, Nelson defines mexFunction, mxArray helpers, mexPrintf, mexLock, and other runtime functions. The modules/mex/src/include/matrix.h file declares the matrix API including mxCreateDoubleMatrix, mxGetPr, and mxIsDouble. These headers are designed to be bit-for-bit compatible with MATLAB's originals.

Runtime Gateway and Symbol Export

The modules/mex/src/include/nlsMex_exports.h file handles symbol export macros (NLSMEX_IMPEXP) for Windows, ensuring generated shared libraries load correctly. The runtime gateway in modules/mex/functions/dlgeneratemexgateway.m generates the bridge code that compiles C sources, creates the shared library (.dll, .so, or .dylib), and forwards calls to your mexFunction with standard nlhs, plhs, nrhs, prhs arguments.

Compiling MEX Files in Nelson

Porting existing MATLAB MEX code requires no source modifications—only a different compilation command.

Place your C source file (e.g., myfunc.c) in your Nelson workspace. Invoke the built-in mex function:

mex('myfunc.c')

Nelson automatically includes the compatibility headers from modules/mex/src/include/. The command compiles the source, links against the Nelson runtime, and produces myfunc.<ext> (platform-specific shared library). Call the function exactly as you would in MATLAB:

result = myfunc(arg1, arg2);

All mxArray handling, memory management, and error reporting function transparently through the compatibility layer.

Practical Code Examples

The following examples demonstrate key MEX API compatibility features using actual Nelson-supported functions.

Hello World MEX Function

This minimal example uses mexPrintf from the compatibility layer:

/* hello.c – a minimal MEX function */
#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
{
    mexPrintf("Hello from Nelson's MEX compatibility layer!\n");
}
% In Nelson interpreter
mex('hello.c');          % Compile
hello();                 % → prints the message

Creating and Returning Numeric Matrices

This example demonstrates mxGetPr, mxCreateDoubleScalar, and error handling:

/* square.c – returns the square of a scalar input */
#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
{
    double *in, *out;
    if (nrhs != 1 || !mxIsDouble(prhs[0])) {
        mexErrMsgTxt("One double scalar input required.");
    }
    in = mxGetPr(prhs[0]);
    plhs[0] = mxCreateDoubleScalar((*in) * (*in));
}
mex('square.c');           % Compile
y = square(3.5);           % y = 12.25

Persistent State with mexLock and mexUnlock

Use mexLock to prevent the shared library from being cleared between calls:

/* counter.c – a persistent counter that survives clearing */
#include "mex.h"

static int count = 0;

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
{
    if (nrhs == 0) {
        count = 0;                /* reset */
        mexUnlock();              /* allow clearing */
        return;
    }
    ++count;
    mexLock();                    /* prevent clearing */
    plhs[0] = mxCreateDoubleScalar((double)count);
}
mex('counter.c');
counter()   % → 1
counter()   % → 2
clear counter   % fails because mexLock keeps the library loaded
counter(0)      % reset and unlock
clear counter   % now succeeds

Callbacks to the Interpreter with mexEvalString

Execute Nelson commands from within C code:

/* eval_demo.c – evaluates a Nelson command from C */
#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[])
{
    mexEvalString("disp('Evaluated from C!')");
}
mex('eval_demo.c');
eval_demo();   % Displays "Evaluated from C!"

Key Source Files and Implementation Details

The MEX API compatibility layer is implemented across these critical paths in the Nelson repository:

Path Description
modules/mex/src/include/mex.h Primary header mirroring MATLAB's mex.h. Defines mexFunction signature, mexPrintf, mexLock, mexUnlock, mexAtExit, and mexEvalString.
modules/mex/src/include/matrix.h Matrix API declarations including mxArray struct, mxCreateDoubleMatrix, mxGetPr, mxIsDouble, and memory management routines.
modules/mex/src/include/engine.h Engine API for mexCallMATLAB-style functionality.
modules/mex/src/include/nlsMex_exports.h Platform abstraction for symbol visibility macros (NLSMEX_IMPEXP).
modules/mex/functions/dlgeneratemexgateway.m Runtime gateway generator that handles compilation, linking, and dynamic loading of MEX shared libraries.
modules/mex/tests/ Comprehensive test suite including test_mexLock.m, test_mexPrintf.m, and other validation scripts ensuring API parity with MATLAB.

These files collectively ensure that the mex built-in command in Nelson provides identical semantics to MATLAB's MEX compiler, including argument passing, memory management, and runtime services.

Summary

  • Nelson's MEX API compatibility layer re-implements MATLAB's mex.h, matrix.h, and engine.h headers to enable unmodified compilation of existing MEX source code.
  • The mex built-in command handles compilation, linking, and dynamic loading automatically, producing platform-specific shared libraries (.dll, .so, .dylib).
  • Key functions like mexLock, mexUnlock, mexEvalString, and mexPrintf provide identical semantics to MATLAB, including persistent state management and interpreter callbacks.
  • Source files in modules/mex/src/include/ and the runtime gateway in modules/mex/functions/dlgeneratemexgateway.m implement the full compatibility stack.

Frequently Asked Questions

What is MEX API compatibility in Nelson?

MEX API compatibility in Nelson is a complete re-implementation of MATLAB's C/C++ MEX interface that allows existing MATLAB MEX source files to compile and execute without modification. It includes header files (mex.h, matrix.h) that mirror MATLAB's API and a runtime system that handles compilation, linking, and execution of the resulting shared libraries.

Do I need to modify my MATLAB MEX source code to run it in Nelson?

No. Nelson's compatibility layer is designed to work with unmodified MATLAB MEX source code. The headers in modules/mex/src/include/ provide identical function signatures, macros, and type definitions (such as mxArray and mxComplexity) that your code already uses. Simply place your .c or .cpp file in the Nelson workspace and call mex('filename.c').

Which MATLAB functions are supported by Nelson's MEX compatibility layer?

Nelson supports the essential MEX API functions including mexFunction (the required entry point), mxCreateDoubleMatrix, mxGetPr, mxIsDouble, mexPrintf, mexErrMsgTxt, mexLock, mexUnlock, mexAtExit, and mexEvalString. However, optional MATLAB-only functions related to graphics engines or specialized toolboxes are not implemented, as Nelson maintains its own graphics and computational subsystems.

How does Nelson handle mexLock and persistent variables in MEX files?

Nelson implements mexLock and mexUnlock to match MATLAB's behavior exactly. When your MEX function calls mexLock(), Nelson increments an internal lock counter that prevents the shared library from being cleared from memory, even if the user attempts clear or clear all. The library persists until mexUnlock() is called enough times to balance the locks, allowing static variables inside your C code to maintain state across multiple function calls.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →