Reputation: 11
I have a FORTRAN code which calls a C routine to calculate a measure. The FORTRAN code is:
program fortran
implicit none
interface
double precision function fpli_hv(A, d, n)
real :: A(5,3)
integer :: d, n
end function fpli_hv
end interface
real :: A(5,3)
double precision :: HV
integer :: i, j
A(1,:) = (/1.1,3.2,2.0/)
A(2,:) = (/6.3,5.2,7.2/)
A(3,:) = (/3.3,4.4,9.1/)
A(4,:) = (/3.3,5.2,2.1/)
A(5,:) = (/7.6,1.7,4.3/)
HV = fpli_hv(A, 3, 5)
end program fortran
The c function looks like this:
double fpli_hv(double *front, int d, int n, double *ref);
In order to club c and fortran, I need to include a Makefil.lib in my makefile. I did so, and prepared my makefile as follows:
# The makefile should contain a set of suffix rules. All suffixes must
# be defined. In this case we will have .o for object files, .c for
# C files, and .f for Fortran files.
.SUFFIXES: .o .c .f90
# LIBRARY:
LIBHV = /gpfs0/home/shafiiha/programs/hv-2.0rc1-src/fpli_hv.a
#include Makefile.lib
# Define the C and Fortran compilers to be used in this makefile:
CC=
FC=gfortran -ffree-form -c
# Define flags to be used by the C and Fortran compilers:
CFLAGS =
FFLAGS =
# Define include to be used by the C and Fortran compilers:
C_INCLUDES =
F_INCLUDES = fortran.f90
# The linker executable in this case must be the MPI Fortran compiler
# to build a mixed C and Fortran MPI code:
LINK = gfortran
# Define values of parameters that appear in the source codes:
DEFINES =
# Define the list of object files for the linker. The linker will use
# those files to build the executable.
OBJECTS = fortran.o
# The rule that makes the drv executable (note that libraries have
# been specified by the mpif90 linker):
fortran: $(OBJECTS)
$(LINK) -o fortran $(OBJECTS) $(LIBHV)
# The rule that makes all object files from C sources:
.c.o:
$(CC) $(CFLAGS) $(C_INCLUDES) $(DEFINES) $<
# The rule that makes all object files from Fortran sources:
.f90.o:
$(FC) $(FFLAGS) $(F_INCLUDES) $^ $(LIBHV)
# The rule for deleting object files no longer needed after using
# make for drv:
clean:
rm *.o
But when I make it, I get this message:
gfortran -o fortran fortran.o /gpfs0/home/shafiiha/programs/hv-2.0rc1-src/fpli_hv.a
fortran.o: In function `MAIN__':
fortran.f90:(.text+0x548): undefined reference to `fpli_hv_'
collect2: ld returned 1 exit status
make: *** [fortran] Error 1
Could you please help me why I get this error? Thanks a lot.
Upvotes: 1
Views: 1043
Reputation: 50927
If you're doing interfaces already (which is great!) then you may as well use the iso_c_binding module which the newest versions of most fortran compilers already have to avoid worrying about underscores and letter cases and what have you:
interface
function fpli_hv(A, d, n) bind(C)
use iso_c_binding
implicit none
real(kind=c_double) :: fpli_hv
integer(kind=c_int), value :: d, n
real(kind=c_float) :: A(5,3)
end function fpli_hv
end interface
Upvotes: 4
Reputation: 29391
In this era the best way to call C from Fortran is to use the ISO C Binding. Your problem is the name mangling that Fortran does by default to avoid collisions with routines of C or standard libraries, typically adding underscores. With the ISO C Binding you can both specify the exact name of the called routine, overriding name mangling, and easily achieve Fortran-C consistency on the arguments. On the Fortran side you write an interface describing the C routine. There have been previous answers here and there are examples in the gfortran manual. The examples aren't unique to gfortran since the ISO C Binding is part of the Fortran 2003 language standard.
Upvotes: 5
Reputation: 60778
Wrap
double fpli_hv(double *front, int d, int n, double *ref);
with
void FPLI_HV_(double *front, int* d, int* n, double *ref, double* returnvalue);
Fortran objects only understand things ending in _ and all function passes are by pointer.
(Edit for below comment).
Upvotes: 0