使 visual studio FORTRAN-C 混合代码 gfortran-gcc 兼容的最小修改
minimum modification to make a visual studio FORTRAN-C mixed code gfortran-gcc compatible
我正在尝试修改 this code (gist as back up) 以兼容 gfortran-gcc。
- 我删除了
[VALUE]
个标签
- 使用
POINTER
和 gfortran 的 -fcray-pointer
标志,而不是 [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);
}
FORTRAN 代码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
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: In function `main':
CMAIN.C:(.text+0x1d): undefined reference to `FACT_(int)'
CMAIN.C:(.text+0x4c): undefined reference to `PYTHAGORAS_(float, float, float*)'
如果你能帮助我知道我将不胜感激:
- 问题是什么,我该如何解决?
- 修改原始代码以使其与 gcc-gfortran 兼容的最佳方法是什么,变化最小。
P.S.1. 也在 Reddit 上分享。
P.S.2. 操作系统和编译器规范与 this question.
相同
Fortran 通过引用传递变量,如任何 Fortran 到 C 教程的第一句话中所述。所以你:
不能只删除[VALUE]
,您应该添加现代VALUE属性或更改C代码以传递指针。
不应在 [REFERENCE]
的 Fortran 端使用指针,而应将其删除。
为您的编译器使用实际的名称修改,现在通常 subroutine_name_
(附加下划线,名称为小写)或使用现代 bind(C, name="binding_name")
属性。
没有现代 Fortran,但有 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")
设置准确的链接符号名称。
除了我的热门评论外,Fortran 通过引用传递,因此您必须修改 .c
和 .for
文件。
下面的代码有效。可能有更简单的方法来声明事物,但这应该 [至少] 让你走得更远。 注意事项:自从 Fortran IV 时代以来,我就没做过多少 Fortran,所以我有点生疏了。我会推迟 Vladimir 的 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
更新:
I get the same undefined reference
error from your code!
啊哈!
我没有提到的一件事 [因为我认为这不会有什么不同] 是我将源文件名更改为使用所有小写字母(例如 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_
fortran 源文件名的更改无关紧要。但是,C 源文件名可以!
更重要的是文件名 后缀(即 .C
更改为 .c
)。
这是因为gcc
会[尝试变得聪明]查看后缀来确定文件是用哪种语言编写的,并进行相应的编译。例如,gcc -c foo.cpp
将编译文件,就好像它是在 c++
中编写的,而 而不是 c
,就好像命令是:g++ -c foo.cpp
虽然 .cpp
是 c++
文件名的 [more] 常用后缀,但 c++
文件的替代后缀是:.C
即大部分项目使用.cpp
约定,但也有部分项目使用.C
约定。 .cpp
优于 .C
的原因之一是 Windows 文件系统不区分大小写。所以,.C
和 .c
看起来是一样的。但是,POSIX 系统(例如 linux、macOSX、iOS、android 等)具有区分大小写的文件名,因此可以使用任何一种约定。
因此,gcc -c CMAIN.C
将编译为 c++
。这会 c++
样式 "name mangling" 符号——这不是我们想要的。在 c++
中,完成修饰以允许 "overloading" 的函数名称。也就是说,两个 [或更多] 不同的函数可以具有相同的名称,只要它们使用不同的参数即可。例如:
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
到 "demangle" 我们得到的 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
我正在尝试修改 this code (gist as back up) 以兼容 gfortran-gcc。
- 我删除了
[VALUE]
个标签 - 使用
POINTER
和 gfortran 的-fcray-pointer
标志,而不是[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);
}
FORTRAN 代码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
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: In function `main':
CMAIN.C:(.text+0x1d): undefined reference to `FACT_(int)'
CMAIN.C:(.text+0x4c): undefined reference to `PYTHAGORAS_(float, float, float*)'
如果你能帮助我知道我将不胜感激:
- 问题是什么,我该如何解决?
- 修改原始代码以使其与 gcc-gfortran 兼容的最佳方法是什么,变化最小。
P.S.1. 也在 Reddit 上分享。 P.S.2. 操作系统和编译器规范与 this question.
相同Fortran 通过引用传递变量,如任何 Fortran 到 C 教程的第一句话中所述。所以你:
不能只删除
[VALUE]
,您应该添加现代VALUE属性或更改C代码以传递指针。不应在
[REFERENCE]
的 Fortran 端使用指针,而应将其删除。为您的编译器使用实际的名称修改,现在通常
subroutine_name_
(附加下划线,名称为小写)或使用现代bind(C, name="binding_name")
属性。
没有现代 Fortran,但有 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")
设置准确的链接符号名称。
除了我的热门评论外,Fortran 通过引用传递,因此您必须修改 .c
和 .for
文件。
下面的代码有效。可能有更简单的方法来声明事物,但这应该 [至少] 让你走得更远。 注意事项:自从 Fortran IV 时代以来,我就没做过多少 Fortran,所以我有点生疏了。我会推迟 Vladimir 的 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
更新:
I get the same
undefined reference
error from your code!
啊哈!
我没有提到的一件事 [因为我认为这不会有什么不同] 是我将源文件名更改为使用所有小写字母(例如 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_
fortran 源文件名的更改无关紧要。但是,C 源文件名可以!
更重要的是文件名 后缀(即 .C
更改为 .c
)。
这是因为gcc
会[尝试变得聪明]查看后缀来确定文件是用哪种语言编写的,并进行相应的编译。例如,gcc -c foo.cpp
将编译文件,就好像它是在 c++
中编写的,而 而不是 c
,就好像命令是:g++ -c foo.cpp
虽然 .cpp
是 c++
文件名的 [more] 常用后缀,但 c++
文件的替代后缀是:.C
即大部分项目使用.cpp
约定,但也有部分项目使用.C
约定。 .cpp
优于 .C
的原因之一是 Windows 文件系统不区分大小写。所以,.C
和 .c
看起来是一样的。但是,POSIX 系统(例如 linux、macOSX、iOS、android 等)具有区分大小写的文件名,因此可以使用任何一种约定。
因此,gcc -c CMAIN.C
将编译为 c++
。这会 c++
样式 "name mangling" 符号——这不是我们想要的。在 c++
中,完成修饰以允许 "overloading" 的函数名称。也就是说,两个 [或更多] 不同的函数可以具有相同的名称,只要它们使用不同的参数即可。例如:
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
到 "demangle" 我们得到的 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