如何正确link gfortran和gcc?
How to properly link gfortran and gcc?
我正在尝试编写一个调用一段 Fortran 代码的 C 函数。我认为直接尝试 link 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)
我写的wrapper如下:
#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
我明白这个错误是什么意思,我可以为显示两个 main
函数的 .o
文件生成 nm
文件。但是,我不确定如何更改 Fortran 代码以消除此错误。
所以我的问题如下:
1. 如何更改 Fortran 或 C 代码来解决此问题?特别是,由于 fortran 代码以 PROGRAM IGRF
开头
- 我是否正确调用了
igrf12syn
例程?我担心我没有正确调用它。我也可能在传递变量方面做得不好,这必须通过引用来完成。
感谢您的帮助,如果我在调用例程时做了一些非常愚蠢的事情,请告诉我。
很久没调用 Fortran 例程了,但你的工作看起来很合理。
现在编写一个简短的 fortran 子程序,将其编译到一个独立的文件中,通过引用子程序参数测试您的调用。
subroutine igrf12syn (isv,date,itype,alt,colat,elong,x,y,z,f)
当然,您可以尝试编译 fortran 文件,只需删除程序行,直至该子例程定义。在我看来它看起来是独立的,但编译器会更好地检查源代码。
首先,您的 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);
这会让编译器满意,虽然它可能不会表达你的意图,
我不清楚。
您明白您不能 link 两个 程序 成为一个程序,
因为 linker 会发现重复的 main
函数。你需要 link
C 主程序仅包含 Fortran 子例程 igrf12syn
.
接下来,下载并保存文件 https://www.ngdc.noaa.gov/IAGA/vmod/igrf12.f
。
在 text/programming 编辑器中打开它。 Select 所有行 - 完整
行,包括前导 space - 组成子例程 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
这些将编译和 link 您的程序作为 testigrf
在同一目录中。
最后,重复前两个命令,每个命令都有附加选项 -Wall
,
查看您尚未注意到的警告。考虑修复程序
删除警告,因为它们很可能意味着程序不会
表现如你所愿。始终在 gcc/g++/gfortran
编译器中包含 -Wall
编译对您重要的代码时的选项。
我正在尝试编写一个调用一段 Fortran 代码的 C 函数。我认为直接尝试 link 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)
我写的wrapper如下:
#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
我明白这个错误是什么意思,我可以为显示两个 main
函数的 .o
文件生成 nm
文件。但是,我不确定如何更改 Fortran 代码以消除此错误。
所以我的问题如下:
1. 如何更改 Fortran 或 C 代码来解决此问题?特别是,由于 fortran 代码以 PROGRAM IGRF
- 我是否正确调用了
igrf12syn
例程?我担心我没有正确调用它。我也可能在传递变量方面做得不好,这必须通过引用来完成。
感谢您的帮助,如果我在调用例程时做了一些非常愚蠢的事情,请告诉我。
很久没调用 Fortran 例程了,但你的工作看起来很合理。
现在编写一个简短的 fortran 子程序,将其编译到一个独立的文件中,通过引用子程序参数测试您的调用。
subroutine igrf12syn (isv,date,itype,alt,colat,elong,x,y,z,f)
当然,您可以尝试编译 fortran 文件,只需删除程序行,直至该子例程定义。在我看来它看起来是独立的,但编译器会更好地检查源代码。
首先,您的 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);
这会让编译器满意,虽然它可能不会表达你的意图, 我不清楚。
您明白您不能 link 两个 程序 成为一个程序,
因为 linker 会发现重复的 main
函数。你需要 link
C 主程序仅包含 Fortran 子例程 igrf12syn
.
接下来,下载并保存文件 https://www.ngdc.noaa.gov/IAGA/vmod/igrf12.f
。
在 text/programming 编辑器中打开它。 Select 所有行 - 完整
行,包括前导 space - 组成子例程 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
这些将编译和 link 您的程序作为 testigrf
在同一目录中。
最后,重复前两个命令,每个命令都有附加选项 -Wall
,
查看您尚未注意到的警告。考虑修复程序
删除警告,因为它们很可能意味着程序不会
表现如你所愿。始终在 gcc/g++/gfortran
编译器中包含 -Wall
编译对您重要的代码时的选项。