【问题标题】:How to properly link gfortran and gcc?如何正确链接 gfortran 和 gcc?
【发布时间】:2016-02-06 19:55:40
【问题描述】:

我正在尝试编写一个调用一段 fortran 代码的 C 函数。我认为尝试直接链接 fortran 代码比尝试将 fortran 重写为 C 更容易。我在直接下载二进制文件并安装它们的 mac 上使用 gcc/g++/gfortran。

fortran 代码位于https://www.ngdc.noaa.gov/IAGA/vmod/igrf12.f。我要调用的具体子程序是subroutine igrf12syn (isv,date,itype,alt,colat,elong,x,y,z,f)

我写的包装如下:

 #include <stdio.h>

 extern void igrf12syn( int *isv, double *year, double *itype, double *alt,
 double *colat, double *elong, double* x,double* y, double* z, double* f );

int main(){
    double B[4], BabsDervs[3], BrDervs[3], BthDervs[3], BphDervs[3];
    double r, th, ph,year,alt2,lat,colat,elong,x,y,z,f;
    int isv;

    // igrf12syn (isv,date,itype,alt,colat,elong,x,y,z,f)
    r = 6371e3;
    th = 0.57;
    ph = 0;

    year = 2015;
    alt2 = 200.0;
    lat = 33.25;
    colat = 90.0-lat;
    elong = 0.0;
    isv =1;
    igrf12syn_(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);

    printf("%0.4e",f);
 return 0;
 }

我用来编译和调用它的命令是:

/usr/local/bin/gcc -lgfortran -c testigrf.c igrf12.f
/usr/local/bin/gcc -lgfortran -o b.out testigrf.o igrf12.o 

我得到的错误是:

duplicate symbol _main in:
testigrf.o
igrf12.o
ld: 1 duplicate symbol for architecture x86_64
collect2: error: ld returned 1 exit status
make: *** [igrf] Error 1

我了解此错误的含义,我可以为 .o 文件生成 nm 文件,其中显示了 main 两个函数。但是,我不确定如何更改 Fortran 代码以消除此错误。

所以我的问题如下: 1. 如何更改 Fortran 或 C 代码来解决此问题?特别是,由于 fortran 代码以 PROGRAM IGRF

开头
  1. 我是否正确调用了igrf12syn 例程?我担心我没有正确调用它。我也可能在传递变量方面做得不好,这必须通过引用来完成。

感谢您的帮助,如果我在调用例程时做了一些非常愚蠢的事情,请告诉我。

【问题讨论】:

  • 没有语言 C/C++,只有两种不同的语言 C 和 C++!你的代码看起来像 C。
  • 不要发布链接。一个问题必须是独立的。另请注意,您的问题包含离题问题,过于宽泛且缺乏信息。阅读How to Ask
  • 该链接已发布,因为我认为将所有代码复制到此帖子中是不值得的。 igrf12.f 属于公共领域。将编辑出问题 3。
  • 另外,我知道 C 和 C++ 是两种不同的语言。但是你可以使用 g++ 和适当的头文件来编译 C 代码。
  • 不,你不能。您可以使用比您想象的更小的通用子集。然而,告诉你不同的是,他们至少不知道他们中的哪些人足以写出比“Hello world”更多的东西。相同的语法并不意味着相同的语义。

标签: c gcc compiler-errors fortran gfortran


【解决方案1】:

首先,您的 C 程序 testigrf.c 有缺陷。照原样, 你有警告:

testigrf.c: In function ‘main’:
testigrf.c:23:5: warning: implicit declaration of function ‘igrf12syn_’ [-Wimplicit-function-declaration]
     igrf12syn_(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);
     ^

这是因为您声明了一个名为 igrf12syn 的函数并调用 一个叫igrf12syn_,编译器对此一无所知。

igrf12syn_改成igrf12syn,重新编译,然后发现的错误是:

testigrf.c: In function ‘main’:
testigrf.c:23:26: warning: passing argument 3 of ‘igrf12syn’ from incompatible pointer type [-Wincompatible-pointer-types]
     igrf12syn(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);
                          ^
testigrf.c:3:14: note: expected ‘double *’ but argument is of type ‘int *’
  extern void igrf12syn( int *isv, double *year, double *itype, double *alt,
              ^
testigrf.c:23:44: error: incompatible type for argument 7 of ‘igrf12syn’
     igrf12syn(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);
                                            ^
testigrf.c:3:14: note: expected ‘double *’ but argument is of type ‘double’
  extern void igrf12syn( int *isv, double *year, double *itype, double *alt,
              ^
testigrf.c:23:46: error: incompatible type for argument 8 of ‘igrf12syn’
     igrf12syn(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);
                                              ^
testigrf.c:3:14: note: expected ‘double *’ but argument is of type ‘double’
  extern void igrf12syn( int *isv, double *year, double *itype, double *alt,
              ^
testigrf.c:23:48: error: incompatible type for argument 9 of ‘igrf12syn’
     igrf12syn(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);
                                                ^
testigrf.c:3:14: note: expected ‘double *’ but argument is of type ‘double’
  extern void igrf12syn( int *isv, double *year, double *itype, double *alt,
              ^
testigrf.c:23:50: error: incompatible type for argument 10 of ‘igrf12syn’
     igrf12syn(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);
                                                  ^
testigrf.c:3:14: note: expected ‘double *’ but argument is of type ‘double’
  extern void igrf12syn( int *isv, double *year, double *itype, double *alt,
              ^

在继续之前,请阅读诊断信息并修复错误。他们 可能会被修复,例如,通过更改:

double r, th, ph,year,alt2,lat,colat,elong,x,y,z,f;

double r, th, ph,year,alt2,lat,colat,elong,x,y,z,f,itype;

和变化:

igrf12syn(&isv,&year,&isv,&r, &th, &ph,x,y,z,f);

到:

igrf12syn(&isv,&year,&itype,&r, &th, &ph,&x,&y,&z,&f);

这将使编译器满意,尽管它可能无法表达您的意图, 我不清楚。

您了解您不能将两个程序链接到一个程序中, 因为链接器会发现重复的main 函数。你需要链接 仅带有 Fortran 子例程 igrf12syn 的 C 主程序。

接下来,下载并保存文件https://www.ngdc.noaa.gov/IAGA/vmod/igrf12.f。 在文本/编程编辑器中打开它。选择所有行 - 完整 行,包括前导空格 - 构成子例程 igrf12syn,来自:

  subroutine igrf12syn (isv,date,itype,alt,colat,elong,x,y,z,f)

到:

 end

将此选择完全保存在新文件igrf12syn.f 中的复制 与testigrf.c 相同的目录。

然后,在该目录中打开一个控制台并执行以下命令:

$ gcc -c -o testigrf.o testigrf.c
$ gfortran -fno-underscoring -c -o igrf12syn.o igrf12syn.f
$ gfortran -o testigrf testigrf.o igrf12syn.o

这些会将您的程序编译并链接为同一目录中的testigrf

最后,重复前两个命令,每个命令都有附加选项-Wall, 查看您尚未意识到的警告。考虑修复程序 删除警告,因为它们很可能意味着程序不会 表现得如你所愿。始终在 gcc/g++/gfortran 编译器中包含 -Wall 编译对您很重要的代码时的选项。

【讨论】:

  • 谢谢迈克,这个答案基本上是正确的。在发布之前,我应该考虑并更加努力地工作。我会注意到,我在 shell 命令中使用了以下命令并且它有效:gcc -lgfortran -c testigrf.c igrf12syn.fgcc -lgfortran -o b.out testigrf.o igrf12syn.o ./b.out
  • @AD0AE 好。然而,gcc -lgfortran -c testigrf.c igrf12syn.fgcc -lgfortran -o b.out testigrf.o igrf12syn.o 的命令都没有任何意义。 (我假设./b.out 有一个换行符)。第一个忽略链接选项-lgfortran,因为-c 表示“仅编译,不链接”。第二个忽略-lgfortran,因为它在链接序列中位于目标文件之前。对我来说,结果是libgfortranlibm 中引用的符号的未定义引用链接错误,这是应该的。如果您使用非常旧的 GCC(我认为是 4.7 之前的版本),那么您的链接将会成功。
【解决方案2】:

我很久没有调用 Fortran 例程了,但你的工作看起来很合理。

现在编写一个简短的 fortran 子例程,将其编译到一个独立文件中,通过引用子例程参数测试您的调用。

      subroutine igrf12syn (isv,date,itype,alt,colat,elong,x,y,z,f)

当然,您可以尝试编译 fortran 文件,只需删除程序行,直至该子例程定义。在我看来,它看起来是独立的,但编译器会更好地检查源代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-21
    • 2010-10-09
    • 2023-03-30
    • 2012-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    相关资源
    最近更新 更多