I tried unsuccessfully to use a polymorphic pointer in a Fortran calling program to represent a specific user defined type in a library that users of the library don't necessarily have access to the module files.
I wrote a Fortran library to handle some empirical data. In the original project, the calling program was written in C. I used modules and then had some specific subroutines that acted as the interface to a C calling program. In essence, C would pass a void pointer to the Fortran library routine that used the iso_c_binding intrinsic module to allocate a pointer of the correct type and then associate the pointer with that pointer. It works really well. However, there is now interest in calling some of the routines through Fortran, and the company distribution program does not handle module files. So, I set out to write a Fortran subroutine wrapper. My original idea was to use a polymorphic pointer, such that a Fortran calling program would not have to know anything about the module in library, something like:
program test class(*), pointer :: fp call finit(fp) call fprint(fp) end program test
where inside of the library subroutine "finit", the pointer is being allocated to the proper type, something like:
subroutine finit(fp) use Point implicit none class(*), pointer :: fp type(TPoint), pointer :: p allocate(p) call init(p) fp => p nullify(p) end subroutine finit
This results in a segmentation fault at the line "fp => p". Inspection with gdb says that the address of fp (0x0) cannot be accessed.
I attached the necessary files to build a simple example, including how I compiled them (see compile.sh). There are three "tests", (1) using the module as if you had access to the mod files - works fine; (2) using the C interface that I talked about above - works fine; and (3) using a subroutine "Fortran" interface to the module - which does not work. The result looks like this:
$./compile.sh test with using module directly x, y: 10.00000 10.00000 test with CInt wrapper x, y: 10.00000 10.00000 test with F wrapper forrtl: severe (174): SIGSEGV, segmentation fault occurred Image PC Routine Line Source a.out 000000000047CC51 Unknown Unknown Unknown a.out 000000000047AD8B Unknown Unknown Unknown a.out 0000000000447FA4 Unknown Unknown Unknown a.out 0000000000447DB6 Unknown Unknown Unknown a.out 00000000004278A7 Unknown Unknown Unknown a.out 0000000000403370 Unknown Unknown Unknown libpthread-2.23.s 00007EFEFBD5B390 Unknown Unknown Unknown a.out 0000000000402C20 finit_ 24 misc.f90 a.out 0000000000402FA5 test_with_f_wrapp 48 misc.f90 a.out 0000000000403199 MAIN__ 10 main.f90 a.out 00000000004029EE Unknown Unknown Unknown libc-2.23.so 00007EFEFB9A0830 __libc_start_main Unknown Unknown a.out 00000000004028E9 Unknown Unknown Unknown
I have several questions, and am hoping someone might at least be able to point me in the right direction (pun intended). Any thoughts are appreciated.
1. Why does this not work; it seems like this is a good use case for polymorphic pointers.
2. Is there a better way to get around having to send module files.
3. I went so far as to look through the iso_c_binding module and mimicked the code there. Instead of using a polymorphic pointer, this requires using an integer pointer "integer(kind=int_ptr_kind()) :: ptr" and then using compiler directive no_arg_check, which I suspect is suppressing the compiler checker from preventing a compile because it can't find a matching "specific subroutine for this generic subroutine call". This method works but I have never used compiler directives in a production code and am a bit leery of the roubustness of the result -- although I use the iso_c_binding module quite frequently which is doing the same thing. Is this the right way around this problem?
I'm using 17.0.0 20160721 on a Linux system; I have also tested this with 12.1.6 20120928 with same results.