1

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?

4

2 回答 2

2

从 Fortran 调用函数时,必须为函数提供显式接口。你正在互相调用它们(在 Fortran 中)。将它们放在一个模块中或使用接口块。

于 2014-01-14T20:34:42.357 回答
2

[编辑,感谢 Vladimir F 和 eriktous 指出标准需要接口;因此指出我原来的(未经测试的)解决方案不太正确。]

绑定标签( 的name=一部分bind(c))是 C 处理器的标识符,因此它特别区分大小写并且在最终符号中不会有 gfortran 风格的装饰)。但是,如果没有可用的接口,gfortran 将CALC2创建对小写符号的引用calc_(如链接器输出中给出的)。

因此,您需要让 gfortran/linker 知道正确的符号。您可以通过提供一个接口来做到这一点。另外,请注意,该标准在bind(c)使用时需要一个显式接口 - 但即使不符合标准,您也可以让它“工作”。

创建显式接口的一种简单方法是使用模块:将子例程放在一个文件中,module calcs/end module calcs在顶部/底部。或者:

subroutine calc(...)
  ...
  interface
    subroutine calc2(...) bind(c, name='CALC2')
      ...
    end subroutine
  end interface
  call CALC2(...)
end subroutine

此外,无论如何,拥有接口是好的,因为它可以进行大量检查。

或者,将绑定标签更改为小写并附加下划线。这可能很有效,但超出了标准和特定于实现的范围。将函数放在单独的文件中会阻碍编译器检测错误的机会。

于 2014-01-14T20:46:21.890 回答