I have the following "C" call back declaration;
typedef void (*ProgCallBackType2)(size_t, int, int, float);
I am trying to call that from Fortran but I get garbage coming through. It works perfectly on GFortran (under linux and macOS). Here are the relevant Fortran bits:
! similar callback routine, with two integer arguments
ABSTRACT INTERFACE
SUBROUTINE ProgressCallBack2(objAddress, loopCompleted, totalLoops, bseYield)
USE, INTRINSIC :: ISO_C_BINDING
INTEGER(c_size_t),INTENT(IN), VALUE :: objAddress
INTEGER(KIND=4), INTENT(IN), VALUE :: loopCompleted
INTEGER(KIND=4), INTENT(IN), VALUE :: totalLoops
REAL(KIND=4),INTENT(IN), VALUE :: bseYield
END SUBROUTINE ProgressCallBack2
END INTERFACE
Then down in the actual Fortran function we make the call:
!--------------------------------------------------------------------------
recursive subroutine EMsoftCgetMCOpenCL(ipar, fpar, atompos, atomtypes, latparm, accum_e, accum_z, cproc, objAddress, cancel) &
bind(c, name='EMsoftCgetMCOpenCL') ! this routine is callable from a C/C++ program
!DEC$ ATTRIBUTES DLLEXPORT :: EMsoftCgetMCOpenCL
TYPE(C_FUNPTR), INTENT(IN), VALUE :: cproc
integer(c_size_t),INTENT(IN), VALUE :: objAddress
character(len=1),INTENT(IN) :: cancel
integer(kind=irg) :: cn, dn, totn
real(kind=sgl),target :: bseyield
......
call proc(objAddress, cn, totn, bseyield)
Back on the C++ side of things I have the following as my Callback function:
void MonteCarloSimulationControllerProgress(size_t instance, int loopCompleted, int totalLoops, float bseYield)
{
std::cout << "MonteCarloSimulationControllerProgress: " << instance << "\t"
<< loopCompleted << "\t" << totalLoops << "\t" << bseYield << std::endl;
}
When I run the program I get utter garbage as the variables. They are not pointers, the actual values are not correct and they are not pointers to pointers (that I can tell). I'm very much a beginner at Fortran (I am working to call this Fortran module from C++) but looking around on Google seems to indicate that we have setup our Fortran code correctly (as evidenced by it working from GFortran).
While trying to figure out what was going on I acted on a hunch and changed the "C" side of things to be the following:
typedef void (*ProgCallBackType2)(size_t*, int*, int*, float*);
void MonteCarloSimulationControllerProgress(size_t* instance, int* loopCompleted, int* totalLoops, float* bseYield)
{
std::cout << "MonteCarloSimulationControllerProgress: " << *instance << "\t"
<< *loopCompleted << "\t" << *totalLoops << "\t" << *bseYield << std::endl;
}
And now I get all the proper values passed through. It seems like Fortran is still passing by reference even though we told it by value? If I leave these changes then GFortran segfaults when running?
This is with version 17.0.4.210 with a build on JULY 2016. Is this a known bug? I can't move to a newer compiler because our fortran code will ICE the next revision of the IFORT so we stuck with this version.
Help. I'm lost.