ctest create_test_sourcelist with fortran and char** - interop

I have some fortran tests I would like to run in CTest using create_test_sourcelist. This is a utility that creates a driver in C or C++, which calls the fortran test routines and expects the signature:
int fortname(int argv, char** argc)
Can someone explain the correct way to interface this signature, probably with iso_c_bindings as I understand these are getting pretty standard. I believe it is the char** that is making me hurt -- there are plenty of examples around for the integer argument.
Thanks!

Assuming that the meaning of argc and argv in the context of a C program's main function apply, then you could do something like:
! Default binding label is already lower case, but for clarity
! it is good practice to specify the binding label explicitly.
function fortname(argc, argv) bind(c, name='fortname')
use, intrinsic :: iso_c_binding, only: c_int, c_ptr
implicit none
!----
! Note C std allows argc == 0
integer(c_int), intent(in), value :: argc
! Lower bound set to match C convention where element 0 probably
! is name of program. May be zero size.
type(c_ptr), intent(in) :: argv(0:argc-1)
! Function result.
integer(c_int) :: fortname
To convert those arguments across to something that is easier to use in Fortran (and further assuming that your Fortran processor supports all applicable parts of the Fortran 2003 standard, noting that deferred length character components are not currently supported by at least one commonly used processor) you could then...
!----
! Name of the program.
character(:), allocatable :: prog_name
! Type to use for arrays of pointers to variable length strings.
type :: string
character(:), allocatable :: item
end type string
! Our arguments. May be zero size.
type(string) :: arguments(argc-1)
integer :: i ! argument index.
!****
if (argc > 0) then ! argv has something useful
! make program name accessible to fortran code.
call c_f_string(argv(0), prog_name)
! make arguments accessible to fortran code.
do i = 1, size(arguments)
call c_f_string(argv(i), arguments(i)%item)
end do
else ! no useful information provided in argv
prog_name = ''
end if
! Work with arguments%item and prog_name...
print "(A)", prog_name
do i = 1, size(arguments) ; print "(A)", arguments(i)%item ; end do
fortname = 0
contains
! Copy a null terminated C string (specified via a non-null c_ptr) to an
! allocatable deferred length default character variable.
subroutine c_f_string(c_string, f_string)
use, intrinsic :: iso_c_binding, only: c_char, c_null_char, c_f_pointer
!----
type(c_ptr), intent(in) :: c_string
character(:), intent(out), allocatable :: f_string
!----
! Array for accessing string pointed at by C pointer
character(kind=c_char), pointer :: string_ptr(:)
integer :: i ! string index
interface
! Steal std C library function rather than writing our own.
function strlen(s) bind(c, name='strlen')
use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t
implicit none
!----
type(c_ptr), intent(in), value :: s
integer(c_size_t) :: strlen
end function strlen
end interface
!****
! Map C pointer to fortran character array
call c_f_pointer(c_string, string_ptr, [strlen(c_string)])
! Allocate fortran character variable to the c string's length
allocate(character(size(string_ptr)) :: f_string)
! Copy across (with possible kind conversion) characters
forall (i = 1:size(string_ptr)) f_string(i:i) = string_ptr(i)
end subroutine c_f_string
end function fortname

Your fortran declaration would be something like this (I think you got argc and argv mixed up so I swapped them):
function fortname(argc, argv) bind(c)
use iso_c_binding
integer(c_int), value :: argc
type(c_ptr) :: argv
end function
You then need to write some code to convert argc to a fortran type. You can convert c pointer to fortran pointers using the c_f_ptr instrinsic. The tricky bit is that you have the double indirection, since fortran doesn't support the concept of a pointer to a pointer. Possibly the following would work, which prints out each argument
type(c_ptr), pointer :: argv_f
character(c_char), pointer :: string_n
call c_f_ptr(argv, argv_f)
do n=1,argc
call_c_f_ptr(argvf(n), string_n)
print *, string_n
end do
Disclaimer: I haven't compiled or run this code!

Related

Fortran dynamic libraries, load at runtime?

Is it possible to have a Fortran program load a Fortran library at run time? If so, would it be possible to modify a function and recompile only the library to have the originally-compiled program call the modified function in the library at run time?
If anyone can provide a minimal working example of how this could be achieved that would be great.
Here are some few links that can be helpfull:
This page on rosettacode.org which gives complete example with details and discuss implementation on linux and MACOS
This intel forum post where Steve Lionel give some advice on how to do the dynamic loading with ifort
this IBM page with a great explanation of dynamic libraries and their usage
If you want a small easy to understand code, keep reading. Few days ago, I was playing with dynamic loading. My test code below might be of help to you. However I work in the linux environment and you might have to adapt few thing here and there for it to work on your OS X environment. The rosettacode.org link above will come handy to help you.
Here is the code for the test dynamic lib
[username#hostname:~/test]$cat test.f90
module test
use, intrinsic :: iso_c_binding
contains
subroutine t_times2(v_in, v_out) bind(c, name='t_times2')
integer, intent(in) :: v_in
integer, intent(out) :: v_out
!
v_out=v_in*2
end subroutine t_times2
!
subroutine t_square(v_in, v_out) bind(c, name='t_square')
integer(c_int), intent(in) :: v_in
integer(c_int), intent(out) :: v_out
!
v_out=v_in**2
end subroutine t_square
end module test
Compiled as
[username#hostname:~/test]$gfortran -c test.f90
[username#hostname:~/test]$gfortran -shared -o test.so test.o
Here is the test program
[username#hostname:~/test]$cat example.f90
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) :: handle
character(256) :: pName, lName
procedure(called_proc), bind(c), pointer :: proc
!
i = 15
handle=dlopen("./test.so"//c_null_char, RTLD_LAZY)
if (.not. c_associated(handle))then
print*, 'Unable to load DLL ./test.so'
stop
end if
!
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
Compiled and run as:
[username#hostname:~/test]$gfortran -o example example.f90 -ldl
[username#hostname:~/test]$./example
t_times2, i2= 30
t_square, i2= 225
[username#hostname:~/test]$

Explicit interface required for subroutines

I am trying to compile a package written mainly in F90 that looks like this:
subroutine soil_default_fill(cgrid,ifm,ipy)
implicit none
!----- Arguments -----------------------------------------------------------------------!
type(edtype) , target :: cgrid
integer , intent(in) :: ifm
integer , intent(in) :: ipy
!----- Local variables -----------------------------------------------------------------!
STUFF
return
end subroutine soil_default_fill
!==========================================================================================!
subroutine set_site_defprops()
implicit none
!----- Local variables -----------------------------------------------------------------!
type(edtype) , pointer :: cgrid
integer :: ifm
integer :: ipy
STUFF
call soil_default_fill(cgrid,ifm,ipy)
STUFF
return
end subroutine set_site_defprops
!==========================================================================================!
When I try to compile I get the following error:
mpif90 -c -DUSE_INTERF=1 -DUSENC=0 -DMAC_OS_X -DUSE_HDF5=1 -DUSE_COLLECTIVE_MPIO=0 -DUSE_MPIWTIME=0 -O3 -ffree-line-length-none -fno-whole-file -I/Users/manfredo/Desktop/ED2/ED/src/include -I/usr/hdf5/include -DRAMS_MPI ed_init.F90
ed_init.F90:131.31:
call soil_default_fill(cgrid,ifm,ipy)
1
Error: Explicit interface required for 'soil_default_fill' at (1): target argument
make[1]: *** [ed_init.o] Error 1
make: *** [all] Error 2
I already tried to include the subroutine in an interface or in a module but it didn't worked (as I said I am new to Fortran so it is likely that I made some mistakes).
Thanks for help
It's a very simple answer but,
Did you set up your module file like this example?
!----------------------------------------------------------!
module "Your Name here (without commas)"
use a_module !!! if you need one, in the other case delete it
use b_module !!! if you need another one, in the other case delete it
implicit none
public :: set_site_defprops !!! put a comment here if you want
public :: soil_default_fill !!! put a comment here if you want
contains
subroutine soil_default_fill(cgrid,ifm,ipy)
implicit none
!----- Arguments ----------------------------------------------------------!
type(edtype) , target :: cgrid
integer , intent(in) :: ifm
integer , intent(in) :: ipy
!----- Local variables ----------------------------------------------------!
STUFF
return
end subroutine soil_default_fill
!==============================================================================!
subroutine set_site_defprops()
implicit none
!----- Local variables -------------------------------------------------!
type(edtype) , pointer :: cgrid
integer :: ifm
integer :: ipy
STUFF
call soil_default_fill(cgrid,ifm,ipy)
STUFF
return
end subroutine set_site_defprops
!==============================================================================!
end module "Your Name here (without commas)"

Interfacing Ada enumerations and C enums

Let in C code are defined:
typedef enum { A=1, B=2 } option_type;
void f(option_type option);
Let we also have Ada code:
type Option_Type is (A, B);
for Option_Type'Size use Interfaces.C.int'Size;
for Option_Type use (A=>1, B=>2);
X: Option_Type := A;
Which of the following code is correct (accordingly RM)?
-- First code
declare
procedure F (Option: Option_Type)
with Import, Convention=>C, External_Name=>"f";
begin
F(X);
end;
or
-- Second code
declare
procedure F (Option: Interfaces.C.unsigned)
with Import, Convention=>C, External_Name=>"f";
function Conv is new Ada.Unchecked_Conversion(Option_Type, Interfaces.C.unsigned);
begin
F(Conv(X));
end;
I think both first and second Ada fragments are correct but am not sure.
Neither is 100% correct.
In C:
typedef enum { A=1, B=2 } option_type;
In Ada:
type Option_Type is (A, B);
for Option_Type'Size use Interfaces.C.int'Size;
for Option_Type use (A=>1, B=>2);
The Ada code assumes that the C type option_type has the same size as a C int. Your second snippet assumes it has the same representation as a C unsigned int.
Neither assumption is supported by the C standard.
Quoting the N1570 draft, section 6.7.2.2, paragraph 4:
Each enumerated type shall be compatible with char, a signed
integer type, or an unsigned integer type. The choice of type is
implementation-defined, but shall be capable of representing the
values of all the members of the enumeration.
So the C type option_type could be as narrow as 1 byte or as wide as the widest supported integer type (typically 8 bytes), and it could be either signed or unsigned. C restricts the values of the enumeration constants to the range of type int, but that doesn't imply that the type itself is compatible with int -- or with unsigned int.
If you have knowledge of the characteristics of the particular C compiler you're using (the phrase "implementation-defined" means that those characteristics must be documented), then you can rely on those characteristics -- but your code is going to be non-portable.
I'm not aware of any completely portable way to define an Ada type that's compatible with a given C enumeration type. (I've been away from Ada for a long time, so I could be missing something.)
The only portable approach I can think of is to write a C wrapper function that takes an argument of a specified integer type and calls f(). The conversion from the integer type to option_type is then handled by the C compiler, and the wrapper exposes a function with an argument of known type to Ada.
void f_wrapper(int option) {
f(option); /* the conversion from int to option_type is implicit */
}

C/C++: char() used as a function

I recently came across the following code that uses syntax I have never seen before:
std::cout << char('A'+i);
The behavior of the code is obvious enough: it is simply printing a character to stdout whose value is given by the position of 'A' in the ASCII table plus the value of the counter i, which is of type unsigned int.
For example, if i = 5, the line above would print the character 'F'.
I have never seen char used as a function before. My questions are:
Is this functionality specific to C++ or did it already exist in strict C?
Is there a technical name for using the char() keyword as a function?
That is C++ cast syntax. The following are equivalent:
std::cout << (char)('A' + i); // C-style cast: (T)e
std::cout << char('A' + i); // C++ function-style cast: T(e); also, static_cast<T>(e)
Stroustroup's The C++ programming language (3rd edition, p. 131) calls the first type C-style cast, and the second type function-style cast. In C++, it is equivalent to the static_cast<T>(e) notation. Function-style casts were not available in C.
This is not a function call, it's instead a typecast. More usually it's written as
std::cout << (char)('A'+i);
That makes it clear it's not a function call, but your version does the same. Note that your version might only be valid in C++, while the one above work in both C and C++. In C++ you can also be more explicit and write
std::cout << static_cast<char>('A'+i);
instead.
Not that the cast is necessary because 'A'+i will have type int and be printed as an integer. If you want it to be interpreted as a character code you need the char cast.

Illegal instruction error when running openMP in gfortran mac

I am new to openMP so bear with me. I use a macbook pro with OX Mavericks and installed a version of gfortran compatible with my OS.
I implemented a very simple dynamic programming problem to solve something that economist call the Neoclassical Growth Model.
I find no problem when I run it without openMP, however when trying to compile the program with -fopenmp option I get either
Illegal Instruction: 4 or
Segmentation Fault: 11
... probably I am doing something very wrong.
I attach the main program, subroutines, modules and .sh compilation file
PROGRAM prg_dp1
! PRG_DP1 SOLVES THE GROWTH MODEL BY VALUE FUNCTION ITERATION OVER A DISCRETE GRID
! WITHOUT INTERPOLATION. EVALUATION IS DONE OVER NEXT PERIOD CAPITAL
! PROBLEM: PROGRAMMED AS MATRICES IT LIMITS THE SIZE OF THE PROGRAM BEFORE !SEGMENTATION FAULTS OCCUR
USE modvar
IMPLICIT NONE
REAL(DP), DIMENSION(nk) :: v,v0,kp,c
REAL(DP), DIMENSION(nk,nk) :: cm,um,vm
REAL(DP) :: kstar,tbegin,tend
INTEGER :: it,ik1,ik2,ind(nk)
! INVOCATION OF THE OUTPUT FILES WHERE THE INFORMATION IS GOING TO BE WRITTEN
CALL CPU_TIME(tbegin)
! DEFINITION OF THE PARAMETERS OF THE MODEL
p(1)=1.0001 ! Intertemporal elasticity of substitution (SIGMA)
p(2)=0.96 ! Intertemporal discount factor (BETA)
p(3)=0.06 ! Depreciation rate (DELTA)
p(4)=0.36 ! Share of capital in production (ALPHA)
p(5)=0.00 ! (Parameter not needed)
! COMPUTATION OF THE STEADY STATE CAPITAL STOCK
kstar=((1.0/p(2)-(1.0-p(3)))/p(4))**(1.0/(p(4)-1.0))
! FIRST I ALLOCATE AND CONSTRUCT THE GRID
slope=1.0
gkmin=0.0001
gkmax=5.0*kstar
! ALLOCATE(gk(nk),ones(nk,nk))
ALLOCATE(gk(nk))
! ones=1.0
CALL sub_grid_generation(gk,nk,slope,gkmin,gkmax)
! DEFINITION OF THE MATRICES OF CONSUMPTION AND UTILITY
!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(ik1,ik2)
!$OMP DO SCHEDULE(DYNAMIC)
DO ik1=1,nk
DO ik2=1,nk
cm(ik1,ik2)=gk(ik1)**p(4)+(1.0-p(3))*gk(ik1)-gk(ik2)
END DO
END DO
!$OMP END DO
!$OMP END PARALLEL
! cm = gk**p(4)+(1.0-p(3))*gk-gk*ones
WHERE (cm .le. 0.0)
um=-1.0e+6
ELSEWHERE
um=(cm**(1.0-p(1))-1.0)/(1.0-p(1))
END WHERE
! DINAMIC PROGRAMMING STEP
! I first initialize the value function to zeros
v0=0.0
! Main do has to be done by master-thread ... can I parallelize more?
DO
!$OMP PARALLEL DO PRIVATE(ik2)
DO ik2=1,nk
vm(:,ik2)=um(:,ik2)+p(2)*v0(ik2)
END DO
!$OMP END PARALLEL DO
v=MAXVAL(vm,DIM=2)
print *, MAXVAL(ABS(v-v0))
IF (MAXVAL(ABS(v-v0)) .le. dp_tol) THEN
EXIT
ELSE
v0=v
END IF
END DO
ind=MAXLOC(v,DIM=1)
kp=gk(ind)
c=gk**p(4)+(1.0-p(3))*gk-kp
open(unit=1,file='output.txt')
DO ik1=1,nk
write(1,'(4F10.5)') gk(ik1),v(ik1),kp(ik1),c(ik1)
END DO
close(1)
DEALLOCATE(gk)
CALL CPU_TIME(tend)
PRINT *, tend-tbegin
END PROGRAM prg_dp1
SUBROUTINE sub_grid_generation(grid,gsize,slope,gridmin,gridmax)
USE nrtype
INTEGER, INTENT(IN) :: gsize
REAL(DP), INTENT(IN) :: slope,gridmin,gridmax
REAL(DP), INTENT(OUT) :: grid(gsize)
INTEGER :: ig
grid(1)=gridmin
DO ig=2,gsize
grid(ig)=gridmin+((gridmax-gridmin)/dfloat(gsize)**slope)*dfloat(ig)**slope
END DO
END SUBROUTINE sub_grid_generation
MODULE nrtype
INTEGER, PARAMETER :: I4B = SELECTED_INT_KIND(9)
INTEGER, PARAMETER :: I2B = SELECTED_INT_KIND(4)
INTEGER, PARAMETER :: I1B = SELECTED_INT_KIND(2)
INTEGER, PARAMETER :: SP = KIND(1.0)
INTEGER, PARAMETER :: DP = KIND(1.0D0)
INTEGER, PARAMETER :: SPC = KIND((1.0,1.0))
INTEGER, PARAMETER :: DPC = KIND((1.0D0,1.0D0))
INTEGER, PARAMETER :: LGT = KIND(.true.)
REAL(SP), PARAMETER :: PI=3.141592653589793238462643383279502884197_sp
REAL(SP), PARAMETER :: PIO2=1.57079632679489661923132169163975144209858_sp
REAL(SP), PARAMETER :: TWOPI=6.283185307179586476925286766559005768394_sp
REAL(SP), PARAMETER :: SQRT2=1.41421356237309504880168872420969807856967_sp
REAL(SP), PARAMETER :: EULER=0.5772156649015328606065120900824024310422_sp
REAL(DP), PARAMETER :: PI_D=3.141592653589793238462643383279502884197_dp
REAL(DP), PARAMETER :: PIO2_D=1.57079632679489661923132169163975144209858_dp
REAL(DP), PARAMETER :: TWOPI_D=6.283185307179586476925286766559005768394_dp
REAL(DP), PARAMETER :: gr=(5.0**0.5-1.0)/2.0
TYPE sprs2_sp
INTEGER(I4B) :: n,len
REAL(SP), DIMENSION(:), POINTER :: val
INTEGER(I4B), DIMENSION(:), POINTER :: irow
INTEGER(I4B), DIMENSION(:), POINTER :: jcol
END TYPE sprs2_sp
TYPE sprs2_dp
INTEGER(I4B) :: n,len
REAL(DP), DIMENSION(:), POINTER :: val
INTEGER(I4B), DIMENSION(:), POINTER :: irow
INTEGER(I4B), DIMENSION(:), POINTER :: jcol
END TYPE sprs2_dp
END MODULE nrtype
MODULE modvar
USE nrtype
IMPLICIT NONE
REAL(DP), PARAMETER :: r_tol=1e-8
REAL(DP), PARAMETER :: p_tol=1e-6
REAL(DP), PARAMETER :: dp_tol=1e-6
REAL(DP), PARAMETER :: c_tol=0.001
REAL(DP), PARAMETER :: adj=0.5
INTEGER, PARAMETER :: r_m=10000
! PARAMETER THAT DEFINE THE DIMENSION OF THE PROBLEM
INTEGER, PARAMETER :: nk=5000
INTEGER, PARAMETER :: nz=21
INTEGER, PARAMETER :: np=20000
INTEGER, PARAMETER :: nt=5000
INTEGER, PARAMETER :: maxit=10000
INTEGER, PARAMETER :: dist_maxit=5000
! POLICY PARAMETER, COMMON ENDOGENOUS VARIABLES AND OTHER ALLOCATABLE ARRAYS
REAL(DP), PARAMETER :: nw=0.0
REAL(DP), PARAMETER :: ft=0.33
REAL(DP) :: p(5),gkmin,gkmax,slope
REAL(DP), ALLOCATABLE :: gk(:),gz(:),m(:,:),mss(:),ones(:,:)
END MODULE modvar
and the .sh file I use to compile
export OMP_NUM_THREADS=8
gfortran -O2 -fopenmp -c nrtype.f90 modvar.f90 sub_grid_generation.f90 prg_dp1.f90
gfortran -O2 -fopenmp -fcheck=bounds -o myprog nrtype.o modvar.o sub_grid_generation.o prg_dp1.o
I know this is tedious but I would appreciate some help
Thank you
The other options is to make the global arrays cm,um,vm, and possibly also the smaller other ones, allocatable. This will become handy when you change the problem size, read it from somewhere and maintain the executable.
REAL(DP), DIMENSION(:,:),allocatable :: cm,um,vm
allocate(cm(nk,nk),um(nk,nk),vm(nk,nk))
It is a stack space issue. I tried running it with ifort and even without openmp I get illegal instruction and I had to specify -heap-arrays in order to get it to run properly. Once I added openmp the illegal instruction error came back. The WHERE statement seems to be the problem code. In both the openmp and non-openmp runs that is the part that causes it to fail
OS X stack space is rather limited and you are creating large arrays. Using -heap-arrays helps, but once you use openmp that is no longer a possibility and ulimit is maxed out as ~64 MB.
I found adding this to your compilation works:
-Wl,-stack_size,0x40000000,-stack_addr,0xf0000000
Which increases the stack size to 1GB. This could probably be fine tuned, but I tried using 256 MB and it was still not enough.

Resources