Совместимость с GNU Fortran и C

У меня есть большая, смешанная база кода C / Fortran, в настоящее время скомпилированная с использованием инструментов Intel в Windows. Меня попросили перенести его на инструменты GNU в Linux. Более-менее случайно я выбрал версию 4.8.

Когда функция C вызывается из Фортрана, взаимодействие часто выглядит следующим образом:

// 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?


person Tom    schedule 15.10.2014    source источник
comment
Боюсь, что у вас может возникнуть более серьезная проблема, связанная с тем, что Intel передает длину как size_t, тогда как GFortran использует int. Это нормально для 32-битных систем, но ужасно ломается в 64-битных системах, передавая более одной строки за раз, и компоновщик даже не улавливает их.   -  person Tristan Brindle    schedule 15.10.2014
comment
Я думаю, что мне просто повезло, и это мне сойдет с рук. Сборка Intel 32-битная.   -  person Tom    schedule 15.10.2014
comment
Я думаю (возможно) компилятором, который имел -fcase-upper, был g95, а не GFortran (который теперь является официальным компилятором GNU Fortran). AFAIK g95 все еще разрабатывается, хотя и медленнее, чем GFortran, но если ваша кодовая база чистая F77 / F95 и не использует передовые функции F2003 / F2008, возможно, стоит изучить?   -  person Tristan Brindle    schedule 15.10.2014
comment
Действительно ли это ~ 2000 различных функций, взаимодействующих от Fortran к C? Или это всего лишь вызовы нескольких функций с разными аргументами? В последнем случае вы можете просто написать несколько оболочек, которые добавят за вас C_NULL_CHAR.   -  person Stefan    schedule 15.10.2014
comment
Если присмотреться, то многие из моих (несколько тысяч) проблем с компоновщиком не связаны с этим. Существует 244 различных функции, взаимодействующих от Fortran к C, которые вызываются 410 раз. Так что это не 2000, но исправить их все тоже нетривиальная попытка.   -  person Tom    schedule 15.10.2014


Ответы (1)


Чтобы устранить ошибку компоновщика, вы можете сделать это иначе. Используйте параметр компилятора Intel names для преобразования внешних имен в нижний регистр в соответствии с GNU Fortran по умолчанию. вариант. И преобразовать имя в c в нижний регистр:

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
person Peter    schedule 15.10.2014