У меня есть старый код Fortran, по разным причинам я модифицирую его, чтобы обеспечить функциональность с помощью C ++.
В этом коде есть две функции, CALC и CALC2. Эти функции должны вызываться из c ++, и они вызывают друг друга.
Эскиз 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
Эскиз 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
Мой текущий 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;
}
Запустив мой файл make, все компилируется правильно, но на этапе компоновки я получаю следующее:
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
Почему это так и как я могу это исправить?
Обязательная этикетка ( 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
Кроме того, наличие интерфейсов, в любом случае, хорошо, так как позволяет много проверять.
В качестве альтернативы измените обязательные метки на строчные и добавьте подчеркивание. Это может хорошо работать, но выходит за рамки стандарта и зависит от конкретной реализации. Наличие функций в отдельных файлах снижает шансы компилятора обнаружить ошибку.
Вы должны предоставить явный интерфейс к функциям при вызове их из Фортрана. И вы звоните им друг от друга (в Фортране). Поместите их в модуль или используйте интерфейсные блоки.