Fortran Coder

标题: C++调用Fortran静态库中的函数 [打印本页]

作者: 安靖    时间: 2017-7-26 11:51
标题: C++调用Fortran静态库中的函数
c++代码中调用由fortran编译的静态库函数在windows(编译器vs2012+intel visual fortran 2013)下,可以成功调用,运行结果正确。
但是移植到linux(编译器c++ f95)下时,在链接时找不到静态库中的函数。

因为fortran代码比较老,所以最好不要对fortran源码进行改动。
附件为测试代码

Linking CXX executable ../bin/Main
CMakeFiles/Main.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x3e): undefined reference to `ADD'
[C++] 纯文本查看 复制代码
#include <cstdio>

extern "C" void ADD(double *, double *, double *);

int main(int argc, char** argv)
{
        double a=10;
        double b=1;
        double sum;
        ADD(&a,&b,&sum);
        printf("a + b = %lf\n", sum);
        return 0;
}



[Fortran] 纯文本查看 复制代码

      subroutine add(a, b, sum)
      real(8) a
      real(8) b
      real(8) sum
      
      sum = a + b
      end






test.zip

5.98 KB, 下载次数: 21

测试例子


作者: fcode    时间: 2017-7-26 19:10
[Fortran] 纯文本查看 复制代码
subroutine add(a, b, sum) Bind(C,Name="ADD")
real(8) a
real(8) b
real(8) sum

sum = a + b
end

作者: pasuka    时间: 2017-7-26 22:25
Mix C Fortran - Ubuntu中文
http://wiki.ubuntu.org.cn/Mix_C_Fortran
Compiling Fortran - Ubuntu中文
http://wiki.ubuntu.org.cn/Compiling_Fortran
作者: 安靖    时间: 2017-7-27 10:53
fcode 发表于 2017-7-26 19:10
[mw_shl_code=fortran,true]subroutine add(a, b, sum) Bind(C,Name="ADD")
real(8) a
real(8) b

感谢你的回答。
按照你的修改,确实是可以生成可执行程序,且结果正确。
不过有没有不修改fortran代码的方式呢
作者: fcode    时间: 2017-7-27 11:13
不修改fortran的话,就修改C++的符号名,但是这可能因为不同编译器的符号修饰不同,而导致代码不通用。

请看如下截图,根据 nm 获得符号名。再对应修改 cpp 代码即可。

nm.png (38.06 KB, 下载次数: 402)

nm.png

作者: 安靖    时间: 2017-7-27 12:03
可能理解不是太准确,但是我想混合编程最主要有两点:
1、注意数据类型的一致。可参考3楼中链接。
2、注意函数名的一致。可以用nm查看生成的对象文件(如*.o)或者库(如*.a)中的函数名字。当链接出现问题时,用nm查看下就应该很明白了。

重点讲讲如何保持函数名一致。
1、就是按照2楼的方法。 保证了生成的库文件中的函数名为ADD,因此,c++在链接时就可以找到函数ADD。采用这种方法应该是最一劳永逸的,当前前提是fortran编译器支持,另外允许你修改fortran代码。

2、如果由于客观条件的限制,无法修改fortran源码时,那么就要先用nm命令查看下生成的对象中函数的真实名字(我估计跟编译器类型或者平台之类的都有关系,这才导致我原来的程序在windows下可以,在linux下就不行了)。
我这里生成的库中函数的名字是add_,所以只需将c++的代码中用到fortran函数的地方就行修改。
[C++] 纯文本查看 复制代码
#include <cstdio>

extern "C" void add_(double *, double *, double *);

int main(int argc, char** argv)
{
        double a=10;
        double b=1;
        double sum;
        add_(&a,&b,&sum);
        printf("a + b = %lf\n", sum);
        return 0;
}


个人理解,如有偏差,大家多多指正。有些专业术语也可能不太准确。
作者: 安靖    时间: 2017-7-27 12:06
fcode 发表于 2017-7-27 11:13
不修改fortran的话,就修改C++的符号名,但是这可能因为不同编译器的符号修饰不同,而导致代码不通用。

请 ...

多谢。 早知道刷新下网页了,不用傻傻地又重复了一遍你说的。

你的回答很直观!(手动点赞)




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2