Use Fortran Subroutine in R? Undefined Symbol

Use Fortran subroutine in R? Undefined symbol

Your problem comes down to the declaration of dboard:

   double precision                ::  pi_est, homepi, pirecv, pisum, dboard

Here you are saying that dboard is an external function, rather than a module procedure. This explains why there is a symbol dboard_ coming into play. You want to remove that:

double precision                ::  pi_est, homepi, pirecv, pisum

and instead rely, in pi on the module procedure-ness of dboard: pi already knows about it without this declaration.

Now, beyond that, because pi is in a module there is going to be some name mangling going on for that subroutine itself. I'd solve this problem by making pi itself a (C) interoperable procedure.

Module Fpi 
IMPLICIT NONE
contains
subroutine pi(avepi, DARTS, ROUNDS) bind(C)
use, intrinsic :: iso_c_binding, only : c_double, c_int
real(c_double), intent(out) :: avepi
integer(c_int), intent(in) :: DARTS, ROUNDS
...

and then using .C rather than .Fortran.

You can keep pi and dboard in the module, and this latter needn't even be interoperable.

R calling Fortran subroutine with character argument

When you use .C to call a Fortran subroutine the calling treats character arguments as being C-style char **. This is not compatible with the Fortran dummy argument of type character(len=255).

You have two 'simple' approaches available:

  • modify the Fortran subroutine to accept arguments looking like char **
  • use .Fortran instead of .C

Modifying the Fortran subroutine to use C interoperability with char ** is better the subject of a new question (for its breadth and being not specific to your R problem). In general, I prefer writing Fortran procedures to be used in R as exposing a C interoperable interface and .C or .Call. With what follows you may also come to that conclusion.

Even the R documentation is not optimistic about passing character arguments with .Fortran:

‘.Fortran’ passes the first (only) character string of a character vector as a C character array to Fortran: that may be usable as ‘character*255’ if its true length is passed separately. Only up to 255 characters of the string are passed back. (How well this works, and even if it works at all, depends on the C and Fortran compilers and the platform.)

You will need to read your documentation about argument passing conventions, such as that for gfortran (consult the appropriate version as these conventions may change).

With .Fortran and gfortran then with a procedure that is not C-interoperable you will need to pass a "hidden" argument to the Fortran procedure specifying the length of the character argument. That is true for explicit length characters (constant length, even length-1, or not) and assumed-length characters.

For gfortran before version 7, this hidden argument is of (R) type integer. Using pow of the question, or with assumed-length argument, we can try something like

bar <- .Fortran("pow", as.character("c"), as.double(x), as.double(0.0), 255L)

Note, however, that this is not standard and inherently not portable. Indeed, as janneb comments and the documentation linked above state, how you pass this hidden argument from R to a gfortran-compiled procedure depends on the version of gfortran used. Using 255L at the end probably won't work beyond gfortran 7. Instead you will need to pass the hidden argument as something matching an integer(c_size_t) (possibly a 64-bit integer). For compilers other than gfortran you may need to do something quite different.

It really is best to use a C-interoperable procedure either with argument interoperable with char ** (using .C) or char [] (using .Fortran). As I say, it's worth going for the first option here, as that leaves more flexibility (like longer characters, more portability, and more character arguments).

Use Fortran subroutine in R? Error: Return type mismatch

You do not use implicit none. That is very bad! Due to implicit typing dboard is thought to he default real inside pi.

Declare it as double precision, or if possible with R, use modules. An interface block can also be used to declare dboard inside pi.

using a Fortran module in R?

Thanks to @roygvib and @francescalus this is my working module:

Module Fortranpi
IMPLICIT NONE
contains
subroutine dboard(darts, dartsscore)
integer, intent(in) :: darts
double precision, intent(out) :: dartsscore
double precision :: x_coord, y_coord
integer :: score, n

score = 0
do n = 1, darts
call random_number(x_coord)
call random_number(y_coord)

if ((x_coord**2 + y_coord**2) <= 1.0d0) then
score = score + 1
end if
end do

dartsscore = 4.0d0*score/darts

end subroutine dboard

subroutine pi(avepi, DARTS, ROUNDS) bind(C, name="pi_")
use, intrinsic :: iso_c_binding, only : c_double, c_int
real(c_double), intent(out) :: avepi
integer(c_int), intent(in) :: DARTS, ROUNDS
integer :: MASTER, rank, i, n
integer, allocatable :: seed(:)
double precision :: pi_est, homepi, pirecv, pisum

! we set it to zero in the sequential run
rank = 0
! initialize the random number generator
! we make sure the seed is different for each task
call random_seed()
call random_seed(size = n)
allocate(seed(n))
seed = 12 + rank*11
call random_seed(put=seed(1:n))
deallocate(seed)

avepi = 0
do i = 0, ROUNDS-1
call dboard(darts, pi_est)
! calculate the average value of pi over all iterations
avepi = ((avepi*i) + pi_est)/(i + 1)
end do
end subroutine pi

end module Fortranpi

Fortran shared lib .so shows undefined symbol error

You must use -assume 2underscore in both compilations, using/not using the option cannot be mixed.
Also extra_fluid2.f90 should be compiled with option -fpic. It's generally a bad idea to use different sets of flags for files that are supposed to go into the same executable or shared object.

WARNING the following symbols are missing

See the mentioned details in 1. In summary:

This local declaration overrides the module function within this
subroutine. Thus the subsequent reference is looking for an external
function of that name, which apparently does not exist, and if it did,
then you would not be computing what you think you are computing. Just
remove this declaration to fix your problem.



Related Topics



Leave a reply



Submit