Call MATLAB Compiler SDK API Functions from C/C++
Shared Library Functions
A C or C++ shared library generated by MATLAB® Compiler SDK™ contains at least seven functions. There are three generated functions to manage library initialization and termination, one each for printed output and error messages, and two generated functions for each MATLAB function included in the library.
To generate the functions described in this section, first copy the folder
to your current working directory.matlabroot
\extern\examples\compilersdk\c_cpp\triangle
Create a shared library named libtriangle
that contains the
function sierpinski.m
by following the procedure in Create a C Shared Library with MATLAB Code, Generate a C++ mwArray API Shared Library and Build a C++ Application, or Generate a C++ MATLAB Data API Shared Library and Build a C++ Application,
depending on the desired target application.
Type of Application
Once your shared library is created, execute the mbuild
command
that corresponds to your target language. This command uses your C/C++ compiler to
compile the code and link the driver code against the MATLAB
Compiler SDK generated C/C++ shared library.
For a C application, use mbuild triangle.c
libtriangle.lib
.
For a C++ mwArray
API application, use mbuild
triangle_mwarray.cpp libtriangle.lib
For a C++ MATLAB Data API application, use mbuild
triangle_mda.cpp
Note
The .lib
extension is for Windows®. On Mac, the file extension is .dylib
, and on
UNIX® it is .so
.
This command assumes that the C/C++ shared library, the driver code, and the corresponding header file are in the current working folder.
These commands create a main program named after the selected source code file
that call function in the libtriangle
shared library. The library
exports a single function (contained in sierpinski.m
) that uses a
simple iterative algorithm to generate the fractal known as Sierpinski's Triangle.
The main program can optionally take a single numeric argument which specifies the
number of points used to generate the fractal. For example, triangle
8000
generates a diagram with 8,000 points.
Structure of Programs That Call Shared Libraries
All programs that call MATLAB Compiler SDK generated shared libraries have roughly the same structure.
Declare variables and process/validate input arguments.
Call the MATLAB Runtime initialization function and test for success. This function sets up the global MATLAB Runtime state and enables the construction of MATLAB Runtime instances.
For a C or C++
mwArray
API application, usemclInitializeApplication
.For a C++ MATLAB Data API application, use
matlab::cpplib::initMATLABApplication
, which optionally takes a vector of run time options such as-nojvm
and-logfile
. The return value is a pointer to aMATLABApplication
object that encapsulates the application state.
Avoid issuing
cd
commands from the application before calling the initialization function. Doing so can cause a failure in MATLAB Runtime initialization.For a C++ MATLAB Data API application, initialize a
matlab::data::ArrayFactory
, which you use to producematlab::data::Array
objects that you pass into function calls.(Optional) Create a run loop to separate the logic of the primary function from the main function. The run loop functions provide a convenient cross platform mechanism for wrapping the execution of MATLAB code in the shared library. On macOS, this handles specific threading issues and fulfills the requirements of the Cocoa API.
For a C or C++
mwArray
API application, usemclRunMain
.Caution
Do not use
mclRunMain
on macOS if your application brings up its own full graphical environment.For a C++ MATLAB Data API application, use
matlab::cpplib::runMain
.
Call the library initialization function once for each library to create the MATLAB Runtime instance required by the library. The function performs library-local initialization. It unpacks the deployable code archive and starts a MATLAB Runtime instance with the necessary information to execute the code in that archive.
For a C or C++
mwArray
API application, use<library>Initialize[WithHandlers]
.For a C++ MATLAB Data API application, use
matlab::cpplib::initMATLABLibrary
ormatlab::cpplib::initMATLABLibraryAsync
.To call a function in an initialized library, call
feval
orfevalAsync
on theunique_ptr
that was returned byinitMATLABLibrary
. There are several overloaded versions of each. They all take the name of the MATLAB function as the first parameter. However, these differ in terms of whether they accept and return singlematlab::data::Array
objects, arrays ofmatlab::data::Array
, or native types. The forms that return a native type must take the type as a template parameter.
Invoke functions in the library and process the results in the main body of the program.
(Optional) If the application displays MATLAB figure windows, call the figure processing function to enable the deployed application to display graphics events.
For a C or C++
mwArray
API application, usemclWaitForFiguresToDie
.For a C++ MATLAB Data API application, use
matlab::cpplib::MATLABLibrary::waitForFiguresToClose
.
For a C or C++
mwArray
API application, call the library termination function<library>Terminate
once for each library to destroy the MATLAB Runtime instance associated with the library. Once a library has been terminated, the functions exported by the library cannot be called again in the application.Call the MATLAB Runtime termination function to free resources associated with the global MATLAB Runtime state. Once you call this function, no further calls can be made to shared libraries in the application.
For a C or C++
mwArray
API application, callmclTerminateApplication
.For a C++ MATLAB Data API application, call the
return()
function on theMATLABApplication
object that was returned bymatlab::cpplib::initMATLABApplication
or allow it to go out of scope. It does not terminate until all the libraries created underneath it have been terminated or gone out of scope.
Clean up variables, close files, etc., and exit.
Library Initialization and Termination Functions
The library initialization and termination functions create and destroy, respectively, the MATLAB Runtime instance required by the shared library. You must call the initialization function before you invoke any of the other functions in the shared library, and you should call the termination function after you are finished making calls into the shared library, or you risk leaking memory.
For C shared libraries and C++ shared libraries using the
mwArray
API, there are multiple forms of the initialization
function <library>Initialize[WithHandlers]
and one of the termination
function <library>Terminate
.
The name of your generated C/C++ shared library is used as part of the function
name. The simplest form of the initialization function takes no arguments; most
likely, this is the version your application will call. In this example, this form
of the initialization function is called
libtriangleInitialize
.
bool libtriangleInitialize(void)
This function creates a MATLAB Runtime instance using the default print and error handlers and other information generated during the compilation process.
However, if you want more control over how printed output and error messages are
handled, call the second form of the function, which takes two arguments. In this
example, this form of the initialization function is called
libtriangleInitializeWithHandlers
.
bool libtriangleInitializeWithKey(
const char* session_key
)
By calling this function syntax, you can provide your own versions of the print and error handling routines called by the MATLAB Runtime. Each of these routines has the same signature (for complete details, see Print and Error Handling Functions). By overriding the defaults, you can control how output is displayed and, for example, whether or not it goes into a log file.
Note
Before calling either form of the library initialization routine, you must
first call mclInitializeApplication
to set up the global
MATLAB Runtime state.
If you have compiled your C++ shared library with an AES encryption key using the
mcc
-k
option, you can use an alternate form of the initialization
function called libtriangleInitializeWithKey
. This syntax allows
you to provide the decryption key at runtime in your C++ application instead of
using a MEX
loader.
bool libtriangleInitializeWithHandlers(
mclOutputHandlerFcn error_handler,
mclOutputHandlerFcn print_handler
)
You can also specify an error handler, print handler, and decryption key using the
syntax libtriangleInitializeWithHandlersAndKey
.
On Microsoft®
Windows platforms, MATLAB
Compiler SDK generates an additional initialization function: the standard
Microsoft DLL initialization function DllMain
.
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason,
void *pv)
The generated DllMain
performs a very important service; it
locates the directory in which the shared library is stored on disk. This
information is used to find the deployable archive, without which the application
will not run. If you modify the generated DllMain
(not
recommended), make sure you preserve this part of its functionality.
Note
On Windows, if you want to have your shared library call a MATLAB shared library, the MATLAB library initialization or termination function (i.e.,
<libname>Initialize, <libname>Terminate
)
cannot be called from your shared library during the
DllMain(DLL_ATTACH_PROCESS)
call. This applies whether
the intermediate shared library is implicitly or explicitly loaded. Place the
call after DllMain()
.
Library termination is straightforward.
void libtriangleTerminate(void)
Call this function (once for each library) before calling
mclTerminateApplication
.
Print and Error Handling Functions
By default, MATLAB Compiler SDK generated applications and shared libraries send printed output to standard output and error messages to standard error. MATLAB Compiler SDK generates a default print handler and a default error handler that implement this policy. If you'd like to change this behavior, you must write your own error and print handlers and pass them in to the appropriate generated initialization function.
You may replace either, both, or neither of these two functions. The MATLAB Runtime sends all regular output through the print handler and all error output through the error handler. Therefore, if you redefine either of these functions, the MATLAB Runtime will use your version of the function for all the output that falls into class for which it invokes that handler.
The default print handler takes the following form.
static int mclDefaultPrintHandler(const char *s)
The implementation is straightforward; it takes a string, prints it on standard
output, and returns the number of characters printed. If you override or replace
this function, your version must also take a string and return the number of
characters “handled.” The MATLAB Runtime calls the print handler when an executing MATLAB file makes a request for printed output, e.g., via the MATLAB function disp
. The print handler does not terminate
the output with a carriage return or line feed.
The default error handler has the same form as the print handler.
static int mclDefaultErrorHandler(const char *s)
However, the default implementation of the print handler is slightly different. It sends the output to the standard error output stream, but if the string does not end with carriage return, the error handler adds one. If you replace the default error handler with one of your own, you should perform this check as well, or some of the error messages printed by the MATLAB Runtime will not be properly formatted.
For an example on using custom print and error handling functions in your
application, see the files located in
.matlabroot
\extern\examples\compilersdk\c_cpp\catcherror
Caution
The error handler does not handle the actual errors, but rather the message
produced after the errors have been caught and handled inside the MATLAB Runtime. You cannot use this function to modify the error handling
behavior of the MATLAB Runtime -- use the try
and catch
statements in your MATLAB files if you want to control how a MATLAB
Compiler SDK generated application responds to an error condition.
Note
If you provide alternate C++ implementations of either
mclDefaultPrintHandler
or
mclDefaultErrorHandler
, then functions must be declared
extern "C"
. For
example:
extern "C" int myPrintHandler(const char *s);
Functions Generated from MATLAB Files
For each MATLAB file specified on the MATLAB
Compiler SDK command line, the product generates two functions, the
mlx
function and the mlf
function. Each of
these generated functions performs the same action (calls your MATLAB file function). The two functions have different names and present
different interfaces. The name of each function is based on the name of the first
function in the MATLAB file (sierpinski
, in this example); each function
begins with a different three-letter prefix.
Note
For C shared libraries, MATLAB
Compiler SDK generates the mlx
and mlf
functions as described in this section. For C++ shared libraries, the product
generates the mlx
function the same way it does for the C
shared library. However, the product generates a modified mlf
function with these differences:
The
mlf
before the function name is dropped to keep compatibility with R13.The arguments to the function are
mwArray
instead ofmxArray
.
mlx Interface Function
The function that begins with the prefix mlx
takes the same
type and number of arguments as a MATLAB MEX-function. (See the External Interfaces documentation for more
details on MEX-functions.) The first argument, nlhs
, is the
number of output arguments, and the second argument, plhs
, is
a pointer to an array that the function will fill with the requested number of
return values. (The “lhs
” in these argument
names is short for “left-hand side” -- the output variables in a
MATLAB expression are those on the left-hand side of the assignment
operator.) The third and fourth parameters are the number of inputs and an array
containing the input variables.
void mlxSierpinski(int nlhs, mxArray *plhs[], int nrhs,
mxArray *prhs[])
mlf Interface Function
The second of the generated functions begins with the prefix
mlf
. This function expects its input and output arguments
to be passed in as individual variables rather than packed into arrays. If the
function is capable of producing one or more outputs, the first argument is the
number of outputs requested by the caller.
void mlfSierpinski(int nargout, mxArray** x, mxArray** y,
mxArray* iterations, mxArray* draw)
In both cases, the generated functions allocate memory for their return
values. If you do not delete this memory (via mxDestroyArray
)
when you are done with the output variables, your program will leak
memory.
Your program may call whichever of these functions is more convenient, as they
both invoke your MATLAB file function in an identical fashion. Most programs will likely
call the mlf
form of the function to avoid managing the extra
arrays required by the mlx
form. The example program
triangle.c
calls mlfSierpinski
.
mlfSierpinski(2, &x, &y, iterations, draw);
In this call, the caller requests two output arguments, x
and y
, and provides two inputs, iterations
and draw
.
If the output variables you pass in to an mlf
function are
not NULL, the mlf
function will attempt to free them using
mxDestroyArray
. This means that you can reuse output
variables in consecutive calls to mlf
functions without
worrying about memory leaks. It also implies that you must pass either
NULL
or a valid MATLAB array for all output variables or your program will fail because
the memory manager cannot distinguish between a non-initialized (invalid) array
pointer and a valid array. It will try to free a pointer that is not NULL --
freeing an invalid pointer usually causes a segmentation fault or similar fatal
error.
Using varargin and varargout in a MATLAB Function Interface
If your MATLAB function interface uses varargin
or
varargout
, you must pass them as cell arrays. For
example, if you have N
varargin
s, you need to create one cell array of size
1-by-N
. Similarly, varargout
s are
returned back as one cell array. The length of the varargout
is equal to the number of return values specified in the function call minus the
number of actual variables passed. As in the MATLAB software, the cell array representing varagout
has to be the last return variable (the variable preceding the first input
variable) and the cell array representing varargin
s has to be
the last formal parameter to the function call.
For information on creating cell arrays, refer to the C MEX function interface in the External Interfaces documentation.
For example, consider this MATLAB file interface:
[a,b,varargout] = myfun(x,y,z,varargin)
The corresponding C interface for this is
void mlfMyfun(int numOfRetVars, mxArray **a, mxArray **b,
mxArray **varargout, mxArray *x, mxArray *y,
mxArray *z, mxArray *varargin)
In this example, the number of elements in varargout
is
(numOfRetVars - 2)
, where 2
represents
the two variables, a
and b
, being
returned. Both varargin
and varargout
are
single row, multiple column cell arrays.
Caution
The C++ shared library interface does not support
varargin
with zero (0) input arguments. Calling your
program using an empty mwArray
results in the packaged
library receiving an empty array with nargin = 1
. The C
shared library interface allows you to call mlfFOO(NULL)
(the packaged MATLAB code interprets this as nargin=0
). However,
calling FOO((mwArray)NULL)
with the C++ shared library
interface causes the packaged MATLAB code to see an empty array as the first input and interprets
nargin=1
.
For example, package some MATLAB code as a C++ shared library using varargin
as the MATLAB function's list of input arguments. Have the MATLAB code display the variable nargin
. Call the
library with function
and it won't package, producing this error message:FOO
()
... 'FOO' : function does not take 0 arguments
mwArray junk;
FOO(junk);
FOO((mwArray)NULL);
nargin=1
. In MATLAB, FOO
()
is
nargin=0
and FOO([])
is
nargin=1
. C++ Interfaces for MATLAB Functions Using varargin
and
varargout
. The C++ mlx
interface for MATLAB functions does not change even if the functions use
varargin
or varargout
. However,
the C++ function interface (the second set of functions) changes if the
MATLAB function is using varargin
or
varargout
.
For examples, view the generated code for various MATLAB function signatures that use varargin
or
varargout
.
Note
For simplicity, only the relevant part of the generated C++ function signature is shown in the following examples.
function varargout
=
foo(varargin
)
function varargout
= foo(i1, i2,
varargin
)
Retrieving MATLAB Runtime State Information While Using Shared Libraries
When using shared libraries, you may call functions to retrieve specific information from the MATLAB Runtime state. For details, see Set and Retrieve MATLAB Runtime Data for Shared Libraries.