минимальная модификация, чтобы сделать визуальную студию FORTRAN-C смешанным кодом, совместимым с gfortran-gcc - PullRequest
0 голосов
/ 03 декабря 2018

Я пытаюсь изменить этот код ( gist как резервную копию ), чтобы он стал gfortran-gcc-совместимым.

  • Я удалил теги [VALUE]
  • , использовал POINTER с флагом -fcray-pointer для gfortran, вместо тега [REFERENCE]
  • удалил __stdcall, потому что попробовал #define __stdcall __attribute__((stdcall)), который вызвал warning: ‘stdcall’ attribute ignored [-Wattributes], теперь вот что у меня есть:

C код CMAIN.C:

#include <stdio.h>

extern int FACT_(int n);
extern void PYTHAGORAS_(float a, float b, float *c);

main()
{
    float c;
    printf("Factorial of 7 is: %d\n", FACT_(7));
    PYTHAGORAS_(30, 40, &c);
    printf("Hypotenuse if sides 30, 40 is: %f\n", c);
}

код ФОРТРАН FORSUBS.FOR:

  INTEGER*4 FUNCTION Fact (n)
  INTEGER*4 n 
  INTEGER*4 i, amt
  amt = 1
  DO i = 1, n
    amt = amt * i
  END DO
  Fact = amt
  END

  SUBROUTINE Pythagoras (a, b, cp)
  REAL*4 a
  REAL*4 b
  POINTER (cp, c)
  REAL*4 c
  c = SQRT (a * a + b * b)
  END

the Makefile:

all:
    gfortran -c FORSUBS.FOR -fcray-pointer
    gcc -c CMAIN.C
    gfortran -o result.out FORSUBS.o CMAIN.o  
    rm -rf *.o

clean :
    rm -rf *.out *~ *.bak *.o

Однако я все равно получаю сообщение об ошибке:

CMAIN.o: В функции `main ':

CMAIN.C :(. Text + 0x1d): неопределенная ссылка на `FACT_ (int) '

CMAIN.C :(. Text + 0x4c): неопределенная ссылка на` PYTHAGORAS_ (float, float, float *) '

Буду признателен, если вы поможете мне узнать:

  • В чем проблема и как я могу ее решить?
  • Каков наилучший способ изменить исходный код, чтобы он стал gcc-gfortran-совместимым с минимальными изменениями.

PS1. также доступен на Reddit , PS2. Характеристики операционной системы и компилятора такие же, как у этого вопроса .

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

В дополнение к моим лучшим комментариям, Fortran передает по ссылке, поэтому вам нужно изменить файлы .c и .for.

Код ниже работает.Может быть более простой способ объявить вещи, но это должно [по крайней мере] продвинуть вас дальше. Предостережение : Я не делал много фортранов со времен Фортрана IV, поэтому я немного заржавел.Я бы предпочел решение Владимира VALUE как лучший путь.


#include <stdio.h>

#if 0
extern int fact_(int n);
extern void pythagoras_(float a, float b, float *c);
#else
extern int fact_(int *n);
extern void pythagoras_(float *a, float *b, float *c);
#endif

int
main(void)
{
    float c;
#if 0
    printf("Factorial of 7 is: %d\n", fact_(7));
#else
    int n = 7;
    printf("Factorial of 7 is: %d\n", fact_(&n));
#endif

#if 0
    pythagoras_(30, 40, &c);
#else
    float a = 30;
    float b = 40;
    pythagoras_(&a, &b, &c);
#endif
    printf("Hypotenuse if sides 30, 40 is: %f\n", c);

    return 0;
}

    INTEGER*4 FUNCTION Fact (n)
    INTEGER*4 n
    INTEGER*4 i, amt
    amt = 1
    DO i = 1, n
        amt = amt * i
    END DO
    Fact = amt
    END

    SUBROUTINE Pythagoras (a, b, c)
    REAL*4 a
    REAL*4 b
    REAL*4 c
    c = SQRT (a * a + b * b)
    END

Вот вывод программы:

Factorial of 7 is: 5040
Hypotenuse if sides 30, 40 is: 50.000000

ОБНОВЛЕНИЕ:

Я получаю ту же ошибку undefined reference из вашего кода!

Ага!

Одна вещь, которую я не упомянул [потому что я не думал, что это будет иметь значение], заключается в том, что я изменил имена исходных файлов, чтобы использовать все строчные буквы (например, CMAIN.C --> cmain.c и FORSUBS.FOR --> forsubs.for)

При этом вывод nm *.o дает:

 cmain.o:
                 U fact_
0000000000000000 T main
                 U printf
                 U pythagoras_

forsubs.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_

Изменение имени файла с исходным кодом на фортране не имеет большого значения.Но имя файла источника C имеет значение!

Более того, это имя файла суффикс (то есть .C изменено на .c).

Это потому, что gcc [попытается быть умным и] посмотрит на суффикс, чтобы определить, на каком языке записан файл, и соответственно скомпилирует.Например, gcc -c foo.cpp скомпилирует файл, как если бы он был написан в c++, а не c, как если бы команда была: g++ -c foo.cpp

Хотя .cpp это [более] обычный суффикс для c++ имени файла, альтернативный суффикс для c++ файлов: .C

То есть большинство проектов используют соглашение .cpp, но некоторые используют.C конвенция.Одна из причин предпочтения .cpp над .C заключается в том, что файловые системы Windows не чувствительны к регистру.Итак, .C и .c будут выглядеть одинаково.Однако системы POSIX (например, linux, macOSX, iOS, android и т. Д.) Имеют имена файлов с учетом регистра, поэтому можно использовать любое соглашение.

Таким образом, gcc -c CMAIN.C будет компилироваться как c++.Это делает c++ стиль «искажения имени» символов - не то, что мы хотим.В c++ искажение сделано, чтобы разрешить «перегрузку» имен функций.То есть две [или более] разные функции могут иметь одно и то же имя, если они используют разные аргументы.Например:

void calc(int val);
void calc(int val1,int val2);
void calc(double fval);

Вот вывод nm *.o, если мы используем CMAIN.C:

 CMAIN.o:
0000000000000000 T main
                 U printf
                 U _Z11pythagoras_PfS_S_
                 U _Z5fact_Pi

FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_

Запуск , что файл через c++filt для"разобрать" c++ имен, которые мы получаем:

 CMAIN.o:
0000000000000000 T main
                 U printf
                 U pythagoras_(float*, float*, float*)
                 U fact_(int*)

FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_

Итак, попробуйте использовать имена файлов в нижнем регистре, если это возможно [это рекомендуется наилучшей практикой].Но, как минимум, не используйте .C

0 голосов
/ 03 декабря 2018

Fortran передает переменные по ссылке, как упоминалось в первых предложениях любого учебника Fortran to C.Итак, вы:

  1. Невозможно просто удалить [VALUE], вы должны добавить современный атрибут VALUE или изменить код C для передачи указателей.

  2. Не следует использовать указатели на стороне Фортрана [REFERENCE], а просто удалить его.

  3. Использовать фактическое искажение имени для вашего компилятора, в наши дни обычно subroutine_name_ (с добавленным подчеркиванием,имя строчное) или используйте современный атрибут bind(C, name="binding_name").

Без современного Фортрана, но с VALUE (это просто PITA без):

  INTEGER*4 FUNCTION Fact (n)
  INTEGER*4, VALUE :: n 
  INTEGER*4 i, amt
  amt = 1
  DO i = 1, n
    amt = amt * i
  END DO
  Fact = amt
  END

  SUBROUTINE Pythagoras (a, b, c) bind(C)
  REAL*4, VALUE :: a
  REAL*4, VALUE :: b
  REAL*4 c
  c = SQRT (a * a + b * b)
  END

, а затем просто измените имена C на строчные (pythagoras_, fact_) ... С атрибутом VALUE вам не нужно вводить все те временные символы C, которые вы видите в другом ответе.bind(C) требуется для VALUE для правильной работы.Это избавит вас от переписывания кода, который вызывает процедуры Fortran.

Для лучшего современного опыта используйте bind(C,name="any_name_you_want"), чтобы установить точное имя символа связи.

...