C/Fortran callback to MATLAB
16 views (last 30 days)
Show older comments
I have a large library (~100K lines of code) written in modern Fortran, out of which I need to call only one function with the following C-signature,
#include <stdint.h>
void runFoo (
// nd
int32_t *
// getFuncFromMatlab(nd, Point(nd)): procedure pointer to the MATLAB function
, double (*)(int *, double [])
// input character vector
, char []
// the length of the input chracter vector
, size_t *
);
Note that this function contains a callback to MATLAB. In other words, MATLAB calls this function, and this DLL function has to call another function in MATLAB provided by the original calling MATLAB function. I can generate a DLL from this library, and it loads in MATLAB via lodlibrary() with the above C header. However, that is no help, and I believe I am seriously missing some fundamental step to make this callback work. What is the best approach to solve this problem? MATLAB mex file compilation is no help either, as it apprently cannot even understand the syntax of modern Fortran, for example, module keyword. appreciate you help very much.
As a side note, as much as I find MATLAB a great standalone computing tool, I also find it terrible for any interoperation with any other languages. Hope this issue gets fixed. Are there any interoperation capabilities in MATLAB that would be equivalent to the simple, yet extremely powerful ctypes package of Python?
19 Comments
Walter Roberson
on 16 Apr 2020
With regards to /usr/bin :
I find it hard to believe that Apple cannot trust MATLAB. This seems to be more of a corporation rivalry than anything else
Apple cares little what Mathworks thinks. Mathworks is not buying many systems from Apple, and not so many people buy Apple systems specifically to run MATLAB. Mathworks is just another customer of the Developer's Program as far as Apple is concerned.
Apple blew off NVIDIA, which is a $US100B+ company; Mathworks is small potatos by comparison. It isn't a matter of corporate rivalry: Mathworks is too small for Apple to notice. Apple makes decision, and Mathworks just has to live with the decisions.
Accepted Answer
James Tursa
on 31 Mar 2020
Maybe this can give you the framework you need. I have made some assumptions about how things are connected. You pass in a char string of the MATLAB function you want called, and the callback function inside the C code calls it using some C native memory as input, simple as that.
The code:
// C = callback_test(fun)
// fun = char string containing the MATLAB function name
// C = the result of the callback
#include "mex.h"
#include <stdlib.h>
#include <stdint.h>
void runFoo (
// nd
int32_t *
// getFuncFromMatlab(nd, Point(nd)): procedure pointer to the MATLAB function
, double (*)(int *, double [])
// input character vector
, char []
// the length of the input chracter vector
, size_t *
);
double callback(int *, double []); // The callback function
char *mname; // MATLAB function name
//-------------------------------------------------------------------------
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int32_t n = 7;
char *thestring = "testing123";
size_t len = 10;
if( nrhs && mxIsChar(prhs[0]) ) {
mname = mxArrayToString(prhs[0]);
mexPrintf("MATLAB function = %s\n",mname);
runFoo( &n, callback, thestring, &len );
}
}
//-------------------------------------------------------------------------
void runFoo (
// nd
int32_t *nd
// getFuncFromMatlab(nd, Point(nd)): procedure pointer to the MATLAB function
, double (*getFuncFromMatlab)(int *, double [])
// input character vector
, char str[]
// the length of the input chracter vector
, size_t *len
)
{
int i, ind;
double *d;
double result;
// Generate some fake data using C native memory
d = (double *) malloc( *nd * sizeof(*d) );
for( i=0; i<*nd; i++ ) {
d[i] = (double) (i+1);
}
// Call the callback function
ind = *nd; // Just in case an int32_t is not the same as an int
result = getFuncFromMatlab( &ind, d );
// Print the results
mexPrintf("Result = %g\n",result);
mexPrintf("String passed = ");
for( i=0; i<*len; i++ ) {
mexPrintf("%c",str[i]);
}
mexPrintf("\n");
// Deallocate the C native memory
free(d);
}
//-------------------------------------------------------------------------
double callback(int *nd, double d[])
{
mxArray *rhs[1], *lhs[1];
double *pr;
double result;
int i;
mexPrintf("Inside callback for function %s\n",mname);
// Create the input argument
rhs[0] = mxCreateUninitNumericMatrix( *nd, 1, mxDOUBLE_CLASS, mxREAL );
// Copy the data (need to get C native memory into MATLAB memory)
pr = (double *) mxGetData( rhs[0] );
for( i=0; i<*nd; i++ ) {
*pr++ = *d++;
}
// Make the call
if( mexCallMATLAB( 1, lhs, 1, rhs, mname ) ) {
mexErrMsgTxt("Callback didn't work");
}
result = mxGetScalar( lhs[0] );
// Free the temporary variables
mxDestroyArray( lhs[0] );
mxDestroyArray( rhs[0] );
//Done
return result;
}
And some sample runs:
>> mex callback_test.c
Building with 'Microsoft Visual C++ 2013 (C)'.
MEX completed successfully.
>> callback_test('sum')
MATLAB function = sum
Inside callback for function sum
Result = 28
String passed = testing123
>> callback_test('prod')
MATLAB function = prod
Inside callback for function prod
Result = 5040
String passed = testing123
>> callback_test('sin')
MATLAB function = sin
Inside callback for function sin
Result = 0.841471
String passed = testing123
>> sin(1)
ans =
0.8415
>> callback_test('garbage')
MATLAB function = garbage
Inside callback for function garbage
Error using callback_test
Undefined function 'garbage' for input arguments of type 'double'.
2 Comments
James Tursa
on 2 Apr 2020
Edited: James Tursa
on 2 Apr 2020
Alas, I have never used MPI. One of the things I always intended to learn someday but as yet haven't found the time. How did you include the compiler flag? Are you sure it is getting to the compiler? E.g., are you building the mex routine via the mex command and modifying the $COMPFLAGS stuff, or are you building the mex routine outside of MATLAB?
You also mention the MATLB engine. Are you running the mex routine within a MATLAB Engine? Are you trying to run multiple MATLAB Engines in parallel using MPI?
More Answers (1)
Bruno Luong
on 14 Sep 2019
Edited: Bruno Luong
on 14 Sep 2019
Not sure what you mean by "Callback". Callback to me is kind of event trigger function like an SW interruption.
Anyway if you have the compiler, you can compile any MATLAB function in C shared library, and call it from external C program.
I have no idea about FORTRAN, but in the pass I have linked fortran (gcc,g77) with MSVSC/Intel-C, a bit tricky but doable.
See Also
Categories
Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!