Can Fortran subroutines be passed as argument to the function called in ccall

I searched and saw documentation and discussions on passing different types of variables but nothing on passing subroutines or functions as argument in ccall. We are in the process of converting our fortran programs. Most are using library optimisation subroutine which need the objective and gradient fonctions to be passed as arguments.
Can functions/subroutines be passed as argument to the function called in ccall?
If so where could I find information or documentation for this; what would be the type to declare in the tuple and how to get a handle on the subroutine to be passed. Would that handle be similar to the function passed as first argument to ccall?

I would recommend writing a thin iso_c_binding wrapper in Fortran90+ (here is an example benchmarks/dopri.f90 at master · OpenAstrodynamics/benchmarks · GitHub) which makes calling Fortran from Julia much easier.

The type in Fortran would then be type(c_funptr), intent(in), value :: func and the corresponding Julia type in the ccall should be Ptr{Cvoid}.

You can get a handle to the function by doing

using Libdl

fortran_lib = dlopen("fortran_library.so")
func_ptr = dlsym(fortran_lib, :fortran_func)

and use it in a ccall

ccall((:iso_c_fortran_func, fortran_lib), Cvoid, (Ptr{Cvoid},), func_ptr)

(Disclaimer: It has been a long time since I last did this and have not had time to try a minimal example.)

7 Likes

Thanks, it is a good starting point. I’ll update this thread after attempting to implement along those lines.

1 Like

Maybe because I’m using gfortran as the fortran compiler but I didn’t need to use explicitly the iso_c_binding wrapper.
Simply using dlsym to get the pointer and declaring Ptr{Cvoid} as type was enough to get it working.
I had some delay in preparing the fortran code (splitting the main in pieces that could be called by Julia), hence the timing of this response.
If anyone as any cautions, warnings about skipping the iso_c_binding wrapper, please share them in this tread.

2 Likes

iso_c_binding is not strictly necessary if your code is simple (e.g. no modules) and targets only a single compiler. I still find it useful because it gives a consistent interface.

If you are targeting different compilers however, it becomes a necessity if you do not want to deal with different name mangling conventions and other headaches.

I was able to run a main in Julia calling a fortran library requiring a call back which I provided by wrapping fortran code in a julia function. The memory for the data was allocated on the Fortran side but to adapt to the the library that will be converted to Julia I will need to allocate the data on the Julia side and have the Fortran code (legacy application) use that data.
The project required other work so the Julia-Fortran handshake part is on pause for now but once the allocation in Julia is completed I plan to document all my findings with examples and publish here.
I don’t feel I master the subject yet but can probably help those starting on the Fortran-Julia path.