user790082
user790082

Reputation: 79

How to use a shared/dynamically linked library in Fortran?

I have a neural network trained in Matlab. Now, I want to use this network in Fortran. So, I followed the instructions given here: https://www.mathworks.com/help/deeplearning/ref/network.genfunction.html:

%% First, train a static network and calculate its outputs for the training data.
[x,t] = bodyfat_dataset;
bodyfatNet = feedforwardnet(10);
bodyfatNet = train(bodyfatNet,x,t);
y = bodyfatNet(x);
%% Next, generate and test a MATLAB function. Then the new function is compiled to a shared/dynamically linked library with mcc.
genFunction(bodyfatNet,'bodyfatFcn');
y2 = bodyfatFcn(x);
accuracy2 = max(abs(y-y2))
mcc -W lib:libBodyfat -T link:lib bodyfatFcn

This leads to the generation of files with extensions .c, .h and .so

In the Fortran code test.F90, I want to be able to compute y_test for a given x_test: y_test = bodyfatNet(x_test); Could you please tell me how this can be done/written?

Here below is my Makefile. I can make an executable from object file test.o and the shared object .so:

FORTRAN_COMPILER=gfortran
#FORTRAN_FLAGS=-O3 -Wall -Wextra -std=f2008 
FORTRAN_FLAGS=-ffree-line-length-none

OBJ2 = libBodyfat.so

SRC1= test.F90
OBJ1 = $(SRC1:.F90=.o)

LIBS     =  $(OBJ1) $(OBJ2)

%.o: %.F90
    @echo 'converting .F90 files to .o'
    $(FORTRAN_COMPILER) $(FORTRAN_FLAGS) -o $@ -c $<

binary: $(LIBS)
    @echo 'make an executable from objet files (.o) and the shared object (.so)'
    $(FORTRAN_COMPILER) $(FORTRAN_FLAGS) -o $@ $(LIBS)
clean:  
    @echo 'cleaning'
    @rm -f *.mod *.o binary

I am not certain if utilizing only ‘.so’ would suffice. But the more general question is how from test.F90 I can use the network.

UPDATE: As suggested by PierU, the problem is more of "how to call C routines from Fortran?". Below, you find the content of the generated .h file and .c file:

/*
 * MATLAB Compiler: 8.2 (R2021a)
 * Date: Wed Feb  8 15:21:13 2023
 * Arguments: "-B""macro_default""-W""lib:libBodyfat""-T""link:lib""bodyfatFcn"
 */

#ifndef libBodyfat_h
#define libBodyfat_h 1

#if defined(__cplusplus) && !defined(mclmcrrt_h) && defined(__linux__)
#  pragma implementation "mclmcrrt.h"
#endif
#include "mclmcrrt.h"
#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif

/* This symbol is defined in shared libraries. Define it here
 * (to nothing) in case this isn't a shared library. 
 */
#ifndef LIB_libBodyfat_C_API 
#define LIB_libBodyfat_C_API /* No special import/export declaration */
#endif

/* GENERAL LIBRARY FUNCTIONS -- START */

extern LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitializeWithHandlers(
       mclOutputHandlerFcn error_handler, 
       mclOutputHandlerFcn print_handler);

extern LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitialize(void);

extern LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatTerminate(void);

extern LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatPrintStackTrace(void);

/* GENERAL LIBRARY FUNCTIONS -- END */

/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */

extern LIB_libBodyfat_C_API 
bool MW_CALL_CONV mlxBodyfatFcn(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);

/* C INTERFACE -- MLX WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */

/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- START */

extern LIB_libBodyfat_C_API bool MW_CALL_CONV mlfBodyfatFcn(int nargout, mxArray** Y, mxArray** Xf, mxArray** Af, mxArray* X, mxArray* _U4b, mxArray* _U4c);

#ifdef __cplusplus
}
#endif
/* C INTERFACE -- MLF WRAPPERS FOR USER-DEFINED MATLAB FUNCTIONS -- END */

#endif

This is the content of .c file:

    /*
 * MATLAB Compiler: 8.2 (R2021a)
 * Date: Wed Feb  8 15:21:13 2023
 * Arguments: "-B""macro_default""-W""lib:libBodyfat""-T""link:lib""bodyfatFcn"
 */

#define EXPORTING_libBodyfat 1
#include "libBodyfat.h"

static HMCRINSTANCE _mcr_inst = NULL; /* don't use nullptr; this may be either C or C++ */

#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif

static int mclDefaultPrintHandler(const char *s)
{
    return mclWrite(1 /* stdout */, s, sizeof(char)*strlen(s));
}

#ifdef __cplusplus
} /* End extern C block */
#endif

#ifdef __cplusplus
extern "C" { // sbcheck:ok:extern_c
#endif

static int mclDefaultErrorHandler(const char *s)
{
    int written = 0;
    size_t len = 0;
    len = strlen(s);
    written = mclWrite(2 /* stderr */, s, sizeof(char)*len);
    if (len > 0 && s[ len-1 ] != '\n')
        written += mclWrite(2 /* stderr */, "\n", sizeof(char));
    return written;
}

#ifdef __cplusplus
} /* End extern C block */
#endif

/* This symbol is defined in shared libraries. Define it here
 * (to nothing) in case this isn't a shared library. 
 */
#ifndef LIB_libBodyfat_C_API
#define LIB_libBodyfat_C_API /* No special import/export declaration */
#endif

LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitializeWithHandlers(
    mclOutputHandlerFcn error_handler,
    mclOutputHandlerFcn print_handler)
{
    int bResult = 0;
    if (_mcr_inst)
        return true;
    if (!mclmcrInitialize())
        return false;
    {
        mclCtfStream ctfStream = 
            mclGetEmbeddedCtfStream((void *)(libBodyfatInitializeWithHandlers));
        if (ctfStream) {
            bResult = mclInitializeComponentInstanceEmbedded(&_mcr_inst,
                                                             error_handler, 
                                                             print_handler,
                                                             ctfStream);
            mclDestroyStream(ctfStream);
        } else {
            bResult = 0;
        }
    }  
    if (!bResult)
    return false;
    return true;
}

LIB_libBodyfat_C_API 
bool MW_CALL_CONV libBodyfatInitialize(void)
{
    return libBodyfatInitializeWithHandlers(mclDefaultErrorHandler, 
                                          mclDefaultPrintHandler);
}

LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatTerminate(void)
{
    if (_mcr_inst)
        mclTerminateInstance(&_mcr_inst);
}

LIB_libBodyfat_C_API 
void MW_CALL_CONV libBodyfatPrintStackTrace(void) 
{
    char** stackTrace;
    int stackDepth = mclGetStackTrace(&stackTrace);
    int i;
    for(i=0; i<stackDepth; i++)
    {
        mclWrite(2 /* stderr */, stackTrace[i], sizeof(char)*strlen(stackTrace[i]));
        mclWrite(2 /* stderr */, "\n", sizeof(char)*strlen("\n"));
    }
    mclFreeStackTrace(&stackTrace, stackDepth);
}


LIB_libBodyfat_C_API 
bool MW_CALL_CONV mlxBodyfatFcn(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
    return mclFeval(_mcr_inst, "bodyfatFcn", nlhs, plhs, nrhs, prhs);
}

LIB_libBodyfat_C_API 
bool MW_CALL_CONV mlfBodyfatFcn(int nargout, mxArray** Y, mxArray** Xf, mxArray** Af, 
                                mxArray* X, mxArray* _U4b, mxArray* _U4c)
{
    return mclMlfFeval(_mcr_inst, "bodyfatFcn", nargout, 3, 3, Y, Xf, Af, X, _U4b, _U4c);
}

Upvotes: 0

Views: 113

Answers (0)

Related Questions