Функции Fortran с интерфейсом C приводят к неопределенным ссылкам, когда они пытаются вызывать друг друга, почему?

У меня есть старый код 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

Почему это так и как я могу это исправить?

1

Решение

[Редактировать, спасибо Владимиру Ф. и 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

Кроме того, наличие интерфейсов, в любом случае, хорошо, так как позволяет много проверять.

В качестве альтернативы измените обязательные метки на строчные и добавьте подчеркивание. Это может хорошо работать, но выходит за рамки стандарта и зависит от конкретной реализации. Наличие функций в отдельных файлах снижает шансы компилятора обнаружить ошибку.

2

Другие решения

Вы должны предоставить явный интерфейс к функциям при вызове их из Фортрана. И вы звоните им друг от друга (в Фортране). Поместите их в модуль или используйте интерфейсные блоки.

2

По вопросам рекламы [email protected]