C/Fortran callback to MATLAB

17 views (last 30 days)
A King
A King on 14 Sep 2019
Commented: A King on 16 Apr 2020
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
A King
A King on 16 Apr 2020
That's fair. Incidentally, do you (or James, now that we ended up on this question,) happen to know how to redirect the stdout from the dylib to the MATLAB command prompt (on macOS)?

Sign in to comment.

Accepted Answer

James Tursa
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
A King
A King on 2 Apr 2020
I followed an example on a NASA page that explained how to compile Fortran mex with extra compile flags, so I extrapolated the approach to Intel icc compiler. For example,
mex CC=icc CFLAGS="/IC:\Program Files (x86)\IntelSWTools\parallel_studio_xe_2019.4.066\compilers_and_libraries_2019\windows\mpi\intel64\include" main.c mydll.lib
That did not work though. Based on the examples I have seen on the web, the MPI-parallelism basically requires starting one MATLAB engine per MPI task. On a side note, I do not think MATLAB officially supports MPI parallelism. But there are several external old packages written for this purpose.

Sign in to comment.

More Answers (1)

Bruno Luong
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.
  1 Comment
A King
A King on 14 Sep 2019
Hi Bruno, Thanks, the code being in Fortran is almost irrelevant here, since modern Fortran enabled virtually full interoperation with C, as if you are dealing with C code instead of Fortran. So here is the situation: The user (me) wants to call subroutine Foo() in this Fortran library, which has the above C interface. I have this library's DLL file compiled by the Intel compiler, but apparently that is not enough. So what other methods exist to call this DLL library function from inside MATLAB?
How can I call this function via MATLAB's loadlibrary()? thanks again.

Sign in to comment.

Products


Release

R2019a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!