- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No files were attached to the original post.
Guessing, but if a procedure has a polymorphic argument, or an argument that is a pointer, it must have an explicit interface.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No files were attached to the original post.
Guessing, but if a procedure has a polymorphic argument, or an argument that is a pointer, it must have an explicit interface.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
File should be there now. I'll try adding the explicit interface.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I had to drop this for a bit, but I am looking at it again. I added an explicit interface to the calling subroutine; the error is identical. Specifically, in the attached misc.f90 (attached to original question in example.tar.gz file), I added the interface to the test_with_f_wrapper:
subroutine test_with_f_wrapper implicit none interface subroutine finit(fp_) class(*), pointer, intent(inout) :: fp_ end subroutine finit end interface class(*), pointer :: fp nullify(fp) call finit(fp) call fprint(fp) end subroutine test_with_f_wrapper
I am still puzzled why setting the polymorphic pointer in routine "finit" does not work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Curious; if I box the pointer, as suggested by Neil Carlson in this thread, it works, but I don't understand why.
For example, changing this routine in misc.f90 (see original question example.tar.gz):
subroutine test_with_f_wrapper implicit none type :: box class(*), pointer :: fp => null() end type box type(box) :: qbox call finit(qbox) call fprint(qbox) end subroutine test_with_f_wrapper
and then modifying the finit, fprint, etc. to operate on a type box, e.g.:
subroutine finit(qbox) use Point implicit none type :: box class(*), pointer :: fp => null() end type box type(box) :: qbox type(TPoint), pointer :: p nullify(qbox%fp) allocate(p) call init(p) qbox%fp => p nullify(p) end subroutine finit
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Severin K. wrote:
.. I am still puzzled why setting the polymorphic pointer in routine "finit" does not work.
IanH's advice to you in Quote #2 was general, applicable in all situations where the indicated dummy arguments are involved. You only followed the advice for subprogram finit, now try doing the same with fprint procedure.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
By the way, instead of your current file misc.f90 which is an ordinary collection of various subroutines, is it possible for you to 'CONTAIN' them in a module, thereby gain all the benefits the Fortran standard provides with MODULEs including with INTERFACEs, host association, and scope of the IMPLICIT statement?
You can then avoid the issue as in your original post with missing explicit interfaces, but you would need to add a USE statement for such a module in your calling program of course.
module misc_m ! modified misc.f90 file use Point use CInt use iso_c_binding implicit none contains subroutine test_with_module type(TPoint), pointer :: p allocate(p) call init(p) call print(p) end subroutine test_with_module subroutine test_with_cint_wrapper type(C_PTR) :: cp call cinit(cp) call cprint(cp) end subroutine test_with_cint_wrapper subroutine finit(fp) class(*), pointer :: fp type(TPoint), pointer :: p allocate(p) call init(p) fp => p nullify(p) end subroutine finit subroutine fprint(fp) class(*), pointer :: fp type(TPoint), pointer :: p select type(fp) type is (TPoint) p => fp call print(p) nullify(p) end select end subroutine fprint subroutine test_with_f_wrapper class(*), pointer :: fp nullify(fp) call finit(fp) call fprint(fp) end subroutine test_with_f_wrapper end module misc_m
program test use misc_m implicit none write(*,*) 'test with using module directly' call test_with_module write(*,*) write(*,*) 'test with CInt wrapper' call test_with_cint_wrapper write(*,*) write(*,*) 'test with F wrapper' call test_with_f_wrapper end program test
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@FortranFan you are right. I didn't look at the error trace close enough. I said "finit" still didn't work, but that was incorrect. In fact, after adding the explicit interface to finit, finit ran fine and the segmentation fault occured in fprint. Adding an explicit interface for both routines works as it should.
To answer your second post, you have to go back to the original question. This example is a simplified code to produce the error that I was seeing. In the actcual program, the issue I have, is that I need a library that can be linked to via Fortran, without access to the module files. I built a C interface module that makes linking to the library via C easy, and I was hoping that I could do something similar via Fortran.
I am glad to understand this a little better than I did. In the end, though, I decided on a completely different approach. The user of the library does not actually need the access to the memory location of the data (what the polymorphic pointer was pointing to). Because of this, I can declare a variable to hold the memory location in the module itself. In the provided example, the module Point would have a variable declared type(TPoint) :: TP for example, and then calls to init and print would not have an argument, but would operate on this module level variable TP. This doesn't make a whole lot of sense with the given example, but it was only an example to illustrate the error that I was seeing in the real code.
Thanks @IanH and @FortranFan.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page