I want to load the same .so file twice as separate instances. Based on the example, I have created the app with two dlopen commands.
However, I was facing some issues and I understood that dlmopen should be used if I am using multiple instances of a same .so. However, I don't know how to pass the arguments. Can someone help me how to do this in GFortran?
My code is as below,
program example
use :: iso_c_binding
implicit none
integer(c_int), parameter :: rtld_lazy=1 ! value extracte from the C header file
integer(c_int), parameter :: rtld_now=2 ! value extracte from the C header file
!
! interface to linux API
interface
function dlopen(filename,mode) bind(c,name="dlopen")
! void *dlopen(const char *filename, int mode);
use iso_c_binding
implicit none
type(c_ptr) :: dlopen
character(c_char), intent(in) :: filename(*)
integer(c_int), value :: mode
end function
function dlsym(handle,name) bind(c,name="dlsym")
! void *dlsym(void *handle, const char *name);
use iso_c_binding
implicit none
type(c_funptr) :: dlsym
type(c_ptr), value :: handle
character(c_char), intent(in) :: name(*)
end function
function dlclose(handle) bind(c,name="dlclose")
! int dlclose(void *handle);
use iso_c_binding
implicit none
integer(c_int) :: dlclose
type(c_ptr), value :: handle
end function
end interface
! Define interface of call-back routine.
abstract interface
subroutine called_proc (i, i2) bind(c)
use, intrinsic :: iso_c_binding
integer(c_int), intent(in) :: i
integer(c_int), intent(out) :: i2
end subroutine called_proc
end interface
! testing the dynamic loading
integer i, i2
type(c_funptr) :: proc_addr
type(c_ptr) :: handle1, handle2
character(256) :: pName, lName
procedure(called_proc), bind(c), pointer :: proc
!
i = 15
handle1=dlopen("./test.so"//c_null_char, RTLD_LAZY)
if (.not. c_associated(handle1))then
print*, 'Unable to load DLL ./test.so - First time'
stop
end if
handle2=dlopen("./test.so"//c_null_char, RTLD_LAZY)
if (.not. c_associated(handle2))then
print*, 'Unable to load DLL ./test.so - Second time'
stop
end if
! If I can use dlmopen() I dont know how to pass the arguments
proc_addr=dlsym(handle, "t_times2"//c_null_char)
if (.not. c_associated(proc_addr))then
write(*,*) 'Unable to load the procedure t_times2'
stop
end if
call c_f_procpointer( proc_addr, proc )
call proc(i,i2)
write(*,*) "t_times2, i2=", i2
!
proc_addr=dlsym( handle, "t_square"//c_null_char )
if ( .not. c_associated(proc_addr) )then
write(*,*)'Unable to load the procedure t_square'
stop
end if
call c_f_procpointer(proc_addr, proc)
call proc(i,i2)
write(*,*) "t_square, i2=", i2
contains
end program example
Update:
Based on the suggestion from Vladmir, I tried below but I get Unable to load DLL ./test.so - Third time,
function dlmopen(lmid_t,filename,mode) bind(c,name="dlmopen")
! void *dlopen(const char *filename, int mode);
use iso_c_binding
implicit none
type(c_ptr) :: dlopen
integer(c_long), value :: lmid_t
character(c_char), intent(in) :: filename(*)
integer(c_int), value :: mode
end function
handle3=dlmopen(1,"./test.so"//c_null_char, RTLD_LAZY)
if (.not. c_associated(handle3))then
print*, 'Unable to load DLL ./test.so - Third time'
stop
end if
This is the base that you can start from, it is a modification of your code and because of the #define macros it requires the cpp flags. You can change the defines to a normal parameter declaration if you want, but just copying the macros from the header is easier.
use iso_c_binding
implicit none
! from dlfcn.h
# define LM_ID_BASE 0 /* Initial namespace. */
# define LM_ID_NEWLM -1 /* For dlmopen: request new namespace. */
integer(c_long) :: dlist = LM_ID_NEWLM
integer(c_int), parameter :: rtld_lazy=1 ! value extracte from the C header file
integer(c_int), parameter :: rtld_now=2 ! value extracte from the C header file
type(c_ptr) :: handle3
interface
function dlmopen(lmid_t,filename,mode) bind(c,name="dlmopen")
! void *dlmopen (Lmid_t lmid, const char *filename, int flags);
use iso_c_binding
implicit none
type(c_ptr) :: dlmopen
integer(c_long), value :: lmid_t
character(c_char), intent(in) :: filename(*)
integer(c_int), value :: mode
end function
end interface
handle3=dlmopen(dlist,"test.so"//c_null_char, RTLD_LAZY)
if (.not. c_associated(handle3))then
print*, 'Unable to load DLL ./test.so - Third time'
stop
end if
end
According to the manual, there are two principal values that you can pass as dlist, either LM_ID_BASE or LM_ID_NEWLM. Their values are defined in the header dlfcn.h that is located ammong other standard C and POSIX headers (/usr/include/ or similar). You should not just pass 1, but one of these two values which happen to be 0 and -1 on my computer.
Related
I am trying to pass MPI communicator from Fortran to C/C++. I am not sure what kind of handle to pass: type(MPI_Comm), MPI_Fint, or just integer. I tried several combinations of mentioned options but either I could not compile or got segmentation fault. The following codes produce the error message:
Program received signal SIGSEGV: Segmentation fault - invalid memory
reference.
Interface
module Tailor_module
use mpi
use, intrinsic :: ISO_C_Binding, only: C_int, C_double, C_char, c_associated
use, intrinsic :: ISO_C_Binding, only: c_ptr, C_NULL_ptr
implicit none
private
interface
function Tailor__getobject(comm) result(optr) bind(C, name="Tailor__getobject")
import c_ptr
implicit none
integer, intent(in), value :: comm
type(c_ptr) :: optr
end function Tailor__getobject
end interface
type(c_ptr), save :: obj = c_null_ptr
public :: Create
CONTAINS
subroutine Create(com)
integer, intent(in) :: com
obj = Tailor__getobject(comm=com)
return
end subroutine Create
end module Tailor_module
Fortran driver
program main
use mpi
use Tailor_module, only : Create
IMPLICIT NONE
integer error
call MPI_Init(error)
call Create(MPI_COMM_WORLD);
call MPI_Finalize (error)
end
C++
typedef void * OpaqueObject;
extern "C"
{
OpaqueObject Tailor__getobject(MPI_Fint *f_handle);
}
OpaqueObject Tailor__getobject(MPI_Fint *f_handle)
{
MPI_Comm comm;
comm = MPI_Comm_f2c(*f_handle);
OpaqueObject s;
return s;
}
Consider the following Fortran module Foo_mod and its submodule Foo_smod,
module CallbackInterface_mod
abstract interface
function getLogFunc4C_proc(ndim,Point) result(logFunc) bind(C)
use, intrinsic :: iso_c_binding, only : c_int32_t, c_double, c_int
integer(c_int32_t), intent(in) :: ndim
real(c_double), intent(in) :: Point(ndim)
real(c_double) :: logFunc
end function getLogFunc4C_proc
end interface
end module CallbackInterface_mod
!***********************************************************************************************************************************
!***********************************************************************************************************************************
module Foo_mod
interface
module subroutine runFoo4C(ndim, getLogFuncFromC, inputString, inputStringLen) bind(C, name="runFoo")
use, intrinsic :: iso_c_binding, only: c_int32_t, c_char, c_funptr, c_f_procpointer, c_size_t
use CallbackInterface_mod, only: getLogFunc4C_proc
implicit none
integer(c_int32_t) , intent(in) :: ndim
character(len=1, kind=c_char), dimension(*), intent(in) :: inputString
integer(c_size_t) , intent(in) :: inputStringLen
type(c_funptr), intent(in), value :: getLogFuncFromC
end subroutine runFoo4C
end interface
contains
subroutine runFoo(ndim, getLogFunc, string)
use CallbackInterface_mod, only: getLogFunc4C_proc
use, intrinsic :: iso_fortran_env, only: RK => real64
implicit none
integer :: ndim
procedure(getLogFunc4C_proc) :: getLogFunc
character(*), intent(in) :: string
real(RK) :: Point(ndim)
character(:), allocatable :: mystring
Point = [1._RK,1._RK]
write(*,*) "Hi again, this is a call from inside runFoo!"
write(*,*) "getLogFunc(2,[1,1]) = ", getLogFunc(ndim,Point)
write(*,*) "string = ", string
end subroutine
end module Foo_mod
!***********************************************************************************************************************************
!***********************************************************************************************************************************
submodule (Foo_mod) Foo_smod
contains
module subroutine runFoo4C(ndim, getLogFuncFromC, InputString, inputStringLen) bind(C, name="runFoo")
use, intrinsic :: iso_c_binding, only: c_double, c_int32_t, c_char, c_funptr, c_f_procpointer, c_size_t
use CallbackInterface_mod, only: getLogFunc4C_proc
implicit none
integer(c_int32_t) , intent(in) :: ndim
character(len=1, kind=c_char), dimension(*), intent(in) :: InputString
integer(c_size_t) , intent(in) :: inputStringLen
type(c_funptr), intent(in), value :: getLogFuncFromC
procedure(getLogFunc4C_proc), pointer :: getLogFunc
real(c_double) :: Point(ndim)
character(:), allocatable :: inputString4tran
integer :: i
write(*,*) "InputString: ", InputString(1:inputStringLen)
allocate( character(len=inputStringLen) :: inputString4tran )
do i=1,inputStringLen
inputString4tran(i:i) = InputString(i)
end do
write(*,*) "inputString4tran: ", inputString4tran
! associate the input C procedure pointer to a Fortran procedure pointer
call c_f_procpointer(cptr=getLogFuncFromC, fptr=getLogFunc)
Point = [1._c_double, 1._c_double]
write(*,*) "getLogFunc(ndim=2, [1._c_double, 1._c_double]): ", getLogFunc( ndim, Point )
call runFoo(ndim, getLogFunc, inputString4tran)
end subroutine runFoo4C
end submodule Foo_smod
Now, this code seems like a perfectly sound Fortran module to me, and indeed it does compile and link successfully to C programs via Intel Fortran Compiler 2018, on both Windows and Linux, and runs correctly. However, when compiled by gfortran 7.3.0, it gives the following error:
gfortran -c ../Foo_mod.f90
../Foo_mod.f90:54:18:
submodule (Foo_mod) Foo_smod
1
Error: BIND(C) attribute at (1) can only be used for variables or common blocks
The problem can be resolved if I remove the bind(c) attribute from the interface of the interoperable subroutine runFoo4C() in module Foo_mod, like the following,
...
module subroutine runFoo4C(ndim, getLogFuncFromC, inputString, inputStringLen) ! bind(C, name="runFoo")
...
However, the Intel Fortran compiler would then complain about the incompatibility of the subroutine's interface in module Foo_mod and the implementation of the subroutine in submodule Foo_smod. This seems to me more like a bug in GFORTRAN, than programming mistake. But your comments are appreciated before I go on to report it.
It is quite clear to me that this is a gfortran bug related to submodules. As that's a fairly recent feature addition, it's not unexpected that there may be bugs here and there.
I will comment that when asking a question such as this here, you are strongly encouraged to provide a Minimal, Complete and Verifiable Example Since you don't show the module that the submodule goes with, we can't verify the issue ourselves without unnecessary extra work.
I am working on a Fortran code. And I have to deal with many different type of output file. So to manage all of them, I use type objects.
Until now, I have compiled my code with gfortran on linux and windows (and ifort on linux) ; and it works as expected.
Because, I want in a close future to integrate GPU parallel computing to my code with OpenACC, I have to be able to compile it with pgfortran (the PGI compiler for Fortran).
Here arrives my problem, the compilation (with pgfortran 18-4-0 on windows) returns me no warning, but at the execute the code crashes with a strange error: [Exit 3221225477] test.exe.
Therefore, I tried to isolate the problem, in order to solve it. I finally get the following MWE:
MODULE VTK_IO
implicit none
type, abstract :: FormatVTK
contains
procedure(VTK_open_file),nopass, deferred :: open_file_VTK
procedure(VTK_close_file),nopass, deferred :: close_file_VTK
end type FormatVTK
type, extends(FormatVTK) :: FormatAscii
contains
procedure, nopass :: open_file_VTK => open_file_ascii
procedure, nopass :: close_file_VTK => close_file_ascii
end type FormatAscii
type, public :: VTKfileHandler
integer :: unit
class(FormatVTK), allocatable :: type
end type VTKfileHandler
abstract interface
subroutine VTK_open_file( fd )
import VTKfileHandler
class(VTKfileHandler), intent(inout) :: fd
end subroutine
subroutine VTK_close_file(fd)
import VTKfileHandler
class(VTKfileHandler), intent(in) :: fd
end subroutine
end interface
contains
subroutine open_file_ascii( fd )
implicit none
class(VTKfileHandler), intent(inout) :: fd
character(len=80) :: f
!-------------------------------------------------------------------------
write(unit=*, fmt=*) 'open_file_ascii: start'
! stop 6969
f='test_file.txt'
open(newunit = fd%unit, &
file = trim(adjustl(f)), &
form = 'FORMATTED', & ! FORMATTED
access = 'STREAM', & ! SEQUENTIAL
action = 'WRITE', &
status = 'REPLACE')
write(unit=fd%unit,fmt='(100A)') "# vtk DataFile Version "
write(unit=*, fmt=*) 'open_file_ascii: end'
end subroutine open_file_ascii
subroutine close_file_ascii(fd)
implicit none
class(VTKfileHandler), intent(in) :: fd
!-------------------------------------------------------------------------
close(unit=fd%unit)
write(unit=*, fmt=*) 'close_file_ascii: done'
end subroutine close_file_ascii
end module vtk_IO
PROGRAM Test_open
USE VTK_IO
IMPLICIT NONE
type :: OutputFile
class (VTKfileHandler), allocatable :: VTKfile
end type OutputFile
type (OutputFile) :: OutsFiles
!----------------------------------------------------------------------------
print*, 'START: Test_open'
Print*,'initialise_outputs: start'
allocate(VTKfileHandler :: OutsFiles%VTKfile )
allocate(FormatAscii :: OutsFiles%VTKfile%type)
Print*,'initialise_outputs: end'
call OutsFiles%VTKfile%type%open_file_VTK(OutsFiles%VTKfile)
call OutsFiles%VTKfile%type%close_file_VTK(OutsFiles%VTKfile)
print*, 'END: Test_open'
END PROGRAM Test_open
It seems like the type-bound procedure open_file_VTK is not targetting the procedure open_file_ascii. I think that the compiler get lost with the type-bounded procedure. For example, if I remove the OutsFiles and use directly a VTKfile in the main, it works. But, of course, I need this embedding type OutputFile, in my big code ; otherwise it would be too easy.
So is it a bug from the compiler ? Or can I do something to solve this problem ?
When we compile (gfortran 5.3 or 7.2) and run the following code, line 9 of the main.f03 ends up in a subroutine that is never called. Can anyone explain why?
main.f03:
program main
use minimalisticcase
implicit none
type(DataStructure) :: data_structure
type(DataLogger) :: data_logger
call data_structure%init()
call data_logger%init(data_structure)
end program
minimalisticcase.f03:
module minimalisticcase
implicit none
type, public :: DataStructure
integer :: i
contains
procedure, pass :: init => init_data_structure
procedure, pass :: a => beginning_of_alphabet
end type
type, public :: DataLogger
type(DataStructure), pointer :: data_structure
contains
procedure, pass :: init => init_data_logger
procedure, pass :: do_something => do_something
end type
contains
subroutine init_data_structure(self)
implicit none
class(DataStructure), intent(inout) :: self
write(*,*) 'init_data_structure'
end subroutine
subroutine beginning_of_alphabet(self)
implicit none
class(DataStructure), intent(inout) :: self
write(*,*) 'beginning_of_alphabet'
end subroutine
subroutine init_data_logger(self, data_structure)
implicit none
class(DataLogger), intent(inout) :: self
class(DataStructure), target :: data_structure
write(*,*) 'init_data_logger'
self%data_structure => data_structure
call self%do_something()
end subroutine
subroutine do_something(self)
implicit none
class(DataLogger), intent(inout) :: self
write(*,*) 'do_something'
end subroutine
end module
On line 40 of 'minimalisticcase.f03' we call 'do_something' of the DataLogger. But instead the 'beginning_of_alphabet' subroutin of DataStructure is executed!
Apparently one can fix this by changing line 13 in 'minimalisticcase.f03' from type(DataStructure), pointer :: data_structure to class(DataStructure), pointer :: data_structure.
But why?
This is a bug in gfortran. I posted it on Bugzilla as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82312. The error is now fixed on the GCC trunk.
A temporary workaround is to encase the pointer assignment in a select type, thusly:
select type (data_structure)
type is (DataStructure)
self%data_structure => data_structure
end select
I'm trying to put together a minimal example for performing user-defined derived type input output in Fortran using ifort compiler version 15. The code posted below is able to read and write accordingly, however after "read" is done executing and while control is being returned to the main program the following error occurs:
(61586,0x7fff7e4dd300) malloc: *** error for object 0x10fa7bac4: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
The UDDTIO routines are called in the program as:
module mod_test
implicit none
type, public :: class_test
integer :: foo
contains
procedure, private :: write_test
procedure, private :: read_test
generic :: write(formatted) => write_test
generic :: read(formatted) => read_test
end type class_test
contains
subroutine write_test(dtv, unit, iotype, v_list, iostat, iomsg)
!
implicit none
!
class(class_test), intent(in) :: dtv
integer , intent(in) :: unit
character(*), intent(in) :: iotype
integer , intent(in) :: v_list(:)
integer , intent(out) :: iostat
character(*), intent(inout) :: iomsg
!
iostat = 0
!
write(unit,'(a,/)') '<foo>'
write(unit,*) dtv%foo
write(unit,'(/)')
write(unit,'(a,/)') '</foo>'
!
end subroutine write_test
subroutine read_test(dtv, unit, iotype, v_list, iostat, iomsg)
!
implicit none
!
class(class_test), intent(inout) :: dtv
integer , intent(in) :: unit
character(*), intent(in) :: iotype
integer , intent(in) :: v_list(:)
integer , intent(out) :: iostat
character(*), intent(inout) :: iomsg
!
read(unit,'(/)')
read(unit,*) dtv%foo
read(unit,'(/)')
read(unit,'(/)')
write(*,*) 'z'
end subroutine read_test
end module mod_test
program main
use mod_test
implicit none
type(class_test) :: test
test%foo = 5
write(*,*) 'writing'
open(unit=1, file='write.out', status='replace', action='write')
write(unit=1,fmt=*) test
close(unit=1)
write(*,*) 'reading'
open(unit=1, file='write.out', status='old', action='read')
read(unit=1,fmt=*) test
close(unit=1)
write(*,*) 'end'
end program main
The problem seems to be with the line break statements '(/)'.
Adding iostat=-1 to the read routine seems "solve" the problem. But why?
UDDTIO procedures are required to define the iostat dummy argument, so that the compiler's runtime can test for error and take the appropriate action.
Note that UDDTIO is a relatively recently implemented feature for that compiler. You need to be using the latest possible compiler version.
If I define the iostat dummy argument appropriately in the read and write UDDTIO procedures, your code runs for me with the current 17.0 beta.
Further UDDTIO issues should be fixed in the initial release of 17.0, which can't be too far away.