Reputation: 1570
I have an old fortran code, for various reasons I am modifying it to provide functionality using c++.
In this code there are two functions, CALC and CALC2. These functions need to be called from the c++ and they call each other.
A sketch of CALC:
SUBROUTINE CALC(W,NW,DW,IDMX,JUMP,POINT) bind(C, name="CALC")
use iso_c_binding
C Some statements
IF (LO(36)) CALL CALC2(W,NW,DW,IDMX, .TRUE., 14)
C More statements
END
A sketch of CALC2:
SUBROUTINE CALC2(W,NW,DW,IDMX,JUMP,POINT) bind(C, name="CALC2")
use iso_c_binding
C Some statements
IF (LO(222)) CALL CALC(W,NW,DW,IDMX, .TRUE., 2)
C More statements
END
My current main.cpp:
extern "C" {
void CALC(double *w, double *nw, double *dw, int *idmx, int* jump, int* point);
void CALC2(double *w, double *nw, double *dw, int *idmx, int* jump, int* point);
}
int main()
{
int length = 600000;
int jump = 0;
int point = 0;
double *w = new double[length];
CALC( w, w, w, &length, &jump, &point);
CALC2( w, w, w, &length, &jump, &point);
return 0;
}
Running my make file everything compiles properly, but come the link phase I get this:
g++ (big list of .o files) -lgfortran -o ecis
b1_calc.o: In function `CALC':
b1_calc.f:(.text+0x16b): undefined reference to `calc2_'
bq_calc.o: In function `CALC2':
bq_calc.f:(.text+0x1e52): undefined reference to `calc_'
bq_calc.f:(.text+0x1ec0): undefined reference to `calc_'
collect2: error: ld returned 1 exit status
make: *** [ecis] Error 1
Why is this the case and how do I fix it?
Upvotes: 1
Views: 1576
Reputation: 32451
[Edit, thanks to Vladimir F and eriktous for pointing out the standard requires the interface; and thus pointing out that my original (untested) solution wasn't quite right.]
The binding label (the name=
part of bind(c)
) is an identifier for the C processor, so in particular it is case sensitive and won't have gfortran-style decorations in the final symbol). However, without an interface available to it, gfortran will in CALC2
create a reference to the lower case symbol calc_
(as given in the linker output).
So, you need to let gfortran/linker know that the correct symbols. You do this by providing an interface. Also, note that the standard requires an explicit interface when bind(c)
is used - but you could get this "to work", even though not standard compliant.
An easy way to create an explicit interface would be to use modules: put the subroutines in one file with module calcs
/end module calcs
at the top/bottom. Or:
subroutine calc(...)
...
interface
subroutine calc2(...) bind(c, name='CALC2')
...
end subroutine
end interface
call CALC2(...)
end subroutine
Also, having interfaces is good, anyway, as it enables a lot of checking.
Alternatively, change the binding labels to lower case and append an underscore. This may well work, but is outside the standard and implementation-specific. Having the functions in separate files is thwarting the compiler's chances to detect the error.
Upvotes: 2
Reputation: 60088
You must provide explicit interface to the functions when calling them from Fortran. And you are calling them from each other (in Fortran). Place them in a module or use interface blocks.
Upvotes: 2