У меня есть большая, смешанная кодовая база C / Fortran, в настоящее время скомпилированная с использованием инструментов Intel для Windows. Меня попросили перенести его на инструменты GNU в Linux. Более или менее наугад я выбрал версию 4.8.
Когда функция C вызывается из Fortran, совместимость часто выглядит так:
// C code:
void PRINTSTR(char *str, size_t len) {
for(int ii = 0; ii < len; ii++) {
putchar(str[ii]);
}
putchar('\n');
}
!Fortran code:
program test
implicit none
call printstr("Hello, world.")
end
Компилятор Intel Fortran всегда генерирует символы в верхнем регистре, так что это прекрасно работает. Но компилятор GNU Fortran всегда генерирует символы в нижнем регистре, поэтому возникает ошибка компоновщика.
Компилятор GNU Fortran имел опцию под названием -fcase-upper
из-за этого он генерировал символы в верхнем регистре, но, похоже, он был слишком настраиваемым для всеобщего блага и был удален (я не совсем уверен, когда).
Можно использовать ISO_C_BINDING
средство, чтобы заставить компилятор генерировать чувствительное к регистру имя:
program test
interface
subroutine printstr(str) bind(C, name='PRINTSTR')
character :: str(*)
end subroutine
end interface
call printstr("Hello, world.")
end
Это устраняет ошибку компоновщика, но меняет способ обработки строковых параметров; параметр длины больше не предоставляется. Таким образом, чтобы использовать этот метод, мне нужно было бы не только добавить определения интерфейса для каждой функции, которая в настоящее время работает таким образом, но также мне нужно изменить способ обработки строк при каждом вызове такой функции, убедившись, что все строки имеют нулевое окончание
Я мог бы пройтись и сделать все такие функции строчными, но, конечно, компилятор Intel по-прежнему генерирует символы в верхнем регистре, так что это сломало бы существующую сборку.
Поскольку существует около 2000 таких функций, это кажется неосуществимым объемом работы. Итак, мой вопрос заключается в следующем: как я могу устранить ошибки связи, не изменяя семантику вызова функции и не нарушая существующую сборку с помощью компиляторов Intel?
Чтобы устранить ошибку компоновщика, вы можете сделать это иначе. Использовать опцию компилятора Intel имена преобразовать внешние имена в строчные, чтобы они соответствовали стандартному варианту GNU Fortran. И преобразовать имя в с в нижнем регистре тоже:
void printstr(char *str, size_t len) {...}
Лично я бы рекомендовал использовать -funderscoring
и Intel /assume:underscore
различать функции, предназначенные для взаимодействия.
// C code:
void printstr_(char *str, size_t len) {...}
!Fortran code:
program test
implicit none
call printstr("Hello, world.")
end