fortran和c++互操作

fortran程序,编译成lib,c++调用,总是出现链接错误。这里按照使用的fortran编译器分别讨论可能的原因:

1 编译器:gcc 6.3

fortran程序编译为静态库后,函数名称小写,后面默认带有下划线,例如_a_()。

而c程序编译后,函数名称的形式是只有前面带有下划线,例如_a()。

c++程序编译后,函数名称的形式是

__Z12SampleAddIntii (SampleAddInt(int, int))

__Z15SampleFunction1v(SampleFunction(void))

如果用extern "c"声明,则形式变为_a()。

可以看出来,如果fortran程序的静态库或者动态库要为c++使用,需要extern "C"声明,而且需要处理下划线。

https://docs.oracle.com/cd/E19205-01/820-1204/6nct259sc/index.html

oracle指南:

Fortran 编译器通常会在入口点定义和调用中都出现的子程序名末尾追加一个下划线 (_)。该惯例不同于具有相同的用户指定名称的 C 过程或外部变量。几乎所有 Fortran 库过程名都有两个前导下划线,以减少与用户指定的子例程名的冲突。

对于下划线问题,有三种常用解决方案:

  • 在 C 函数中,通过在函数名末尾追加下划线来更改该名称。

  • 使用 BIND(C) 属性声明来指明外部函数是 C 语言函数。

  • 使用 f95 -ext_names 选项编译对无下划线的外部名称的引用。

只能使用上述解决方案中的一种。

本章的示例都可以使用 BIND(C) 属性声明来避免下划线。BIND(C) 声明可从 Fortran 调用的 C 外部函数,以及可从 C 中作为参数调用的 Fortran 例程。Fortran 编译器在处理外部名称时通常不追加下划线。BIND(C) 必须出现在每个包含这样的引用的子程序中。惯常用法是:

 
       FUNCTION ABC
        EXTERNAL XYZ
        BIND(C) ABC, XYZ

在此处,用户不仅指定 XYZ 是外部 C 函数,而且还指定 Fortran 调用程序 ABC 应该可以从 C 函数调用。如果使用 BIND(C),C 函数不需要在函数名末尾追加下划线。

编译:

http://wiki.ubuntu.org.cn/index.php?title=Mix_C_Fortran&variant=zh-cn

https://blog.csdn.net/vspiders/article/details/52787244

下面的三条命令编译源文件并链接成一个可执行文件:

$ gfortran -c showhie.f -o showhie.o
$ gcc -c c2fortran.c -o c2fortran.o
$ gfortran c2fortran.o showhie.o -o c2fortran

注意最后是用gfortran进行连接。因为gfortran知道如何连接fortran库文件。例如,fortran程序中用到了write *.*,会调用__gfortran_st_write等库函数,或者fortran程序中有数学函数,这时或者gfortran连接,或者手动自己连接fortran库文件(可能是libgfortran、libquadmath等)。

备忘:

gfortran.exe -Li:\softex\fortran_lib_test\bin\Release i:\softex\c_lib_test\Untitled1.o -lstdc++ i:\softex\fortran_lib_

test\bin\Release\libfotran_lib_test.a -o i:\softex\c_lib_test\Untitled1.exe

最后生成的程序还需要gcc的一些动态链接库才能运行,或者拷贝至exe目录,或者添加path环境变量。

2 intel编译器 2013

fortran程序编译后,函数名默认是大写,后面不带下划线,比如_A()的形式。c或者c++只需extern "C" A()声明即可,即声明以c的形式调用库函数。

调用形式:A(),c程序编译完成后的形式是_A()。与fortran相符。

3 编译链接

http://blog.sina.com.cn/s/blog_6798850f0101daea.html

c程序使用visual studio编译时,存在找不到ifconsol.lib问题,需要添加ivf编译器Lib文件目录,然后添加ifconsol.lib。然后,代码生成选项改为fortran库文件编译时的选项,两者必须一致。即都是debug/release,都是mt/md等。

c程序使用gcc编译,fortran代码文件采用gfortran编译生成静态链接库lib。gcc编译命令如下:

gcc 源文件.cpp -o 源文件.exe -l fortran库名 -l libstdc++ -l gfortran

fortran库名,比如静态库名称为libfunc1.a,库名就是func1。

4 参考资料

4.1 intel编译选项的解释

https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/298249

If you have matching C (or C++) and Fortran compilers, there will not be a discrepancy on account of leading underscores. However, ifort for Windows will default to upper case linkage identifiers without underscore conflicts with Windows C. You could correct the case in a standard compliant manner by specifying an iso_c_binding Fortran interface, and removing the _stdcall on the C side. Microsoft dropped full support for stdcall about 7 years ago, and so the cases where it could be used are limited. If you are still using CVF, of course, you have to deal with stdcall.

At least two problems here. 1) You have __stdcall in the C++ declaration but Intel Fortran uses the C mechanism. Remove it. 2) You spell the routine name in lowercase in the C++ declaration but call it with the uppercase name. As far as C++ is concerned, these are two separate routines.

To fix. Take out the __stdcall and change the case of the declaration to be uppercase. Remove the ALIAS directive in the Fortran code.

Alternative. This for the C++:

extern "C"
double pt_h_gas(double p ,double t,float SO2,float H2O,float CO2,float N2,float O2,float Ar,float He,float unit);
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
float SO2 , H2O, CO2, N2, O2,Ar,He, unit;
double enthalpy;
double p,t;
enthalpy = pt_h_gas (p ,t,SO2,H2O,CO2,N2,O2,Ar, He,unit);
}

and this for the Fortran:

Function pt_h_gas(p , t, y1, y2, y3, y4, y5, y6, y7,unit) bind(C)
use iso_c_binding
real(C_DOUBLE) :: pt_h_gas
real(C_FLOAT), value:: y1, y2, y3, y4, y5, y6, y7, unit
real(C_DOUBLE) :: p, t

https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/278963

      -names <keyword>

               Specifies       how source code identifiers and external

               names are interpreted.  The following  are  -names

               options:

               � -names as_is

                   Causes     the compiler to distinguish case differ�

                   externalnames.

               � -names lowercase

                   Causesthe compiler to ignore case differences in identifiers and to convert external names to lowercase.     This is the default.

               � -names uppercase

                   Cause sthe compiler to ignore case differences in identifier sand to convert  external names  to uppercase.

You showed the commands used to compile the sources in thislibrary. These included /names:lowercasse and /assume:underscore. Those are conventions for UNIX/Linux and are different from the default conventions forIntel Fortran on Windows. The mismatch results in the routines not being found.

I suppose the simplest approach, though one I don't like, is toadd those same options to your compiles. In your Fortran project, go to theExternal Procedures property page. Change "Name Case Interpretation"to "Lower Case" and "Append Underscore to External Names"to "Yes", then rebuild.

My preference would be to write interface blocks for these routines that specify BIND(C,NAME="name_") for each one, but that is a lot of work.

4.2 objdump/dumpbin使用

查看符号表: objdump -t xxx.so 。-T 和 -t 选项在于 -T 只能查看动态符号,如库导出的函数和引用其他库的函数,而 -t 可以查看所有的符号,包括数据段的符号。

dumpbin /SYMBOLS file.lib,其中会显示库中的函数名,如_A()。

4.3 gcc/g++ 命令的常用选项格式

-o FILE           指定输出文件名,在编译为目标代码时,这一选项不是必须的。如果FILE没有指定,缺省文件名是a.out.

-c           只编译生成目标文件,不链接

-m486        针对 486 进行代码优化。

-O0          不进行优化处理。

-O 或 -O1  优化生成代码。

-O2          进一步优化。

-O3 比 -O2 更进一步优化,包括 inline 函数。

-w           关闭所有警告,建议不要使用此项

-Wall        允许发出gcc能提供的所有有用的警告,也可以用-W(warning)来标记指定的警告

-werror      把所有警告转换为错误,以在警告发生时中止编译过程                          

-MM          输出一个make兼容的相关列表

-v           显示在编译过程的每一步中用到的命令

-E           只运行 C 预编译器。

-shared      生成共享目标文件。通常用在建立共享库时。

-static      链接静态库,即执行静态链接

-lFOO        链接名为libFOO的函数库

-g           在可执行程序中包含标准调试信息

-ggdb        在可执行程序中包含只有GNU debugger才能使别的达两条是信息

-O           优化编译过的代码

-ON          指定代码优化的级别为N,o<=N<=3

-ansi        支持ANSI/ISO C的标准语法,取消GNU的语法扩展中与该标准有冲突的部分(但这一选项并不能保证生成ANSI兼容的代码) 这一选项将禁止 GNU C 的某些特色, 例如 asm 或 typeof 关键词。

-pedantic  允许发出ANSI/ISO C标准所列出的所有警告

-errors      允许发出ANSI/ISO C标准所列出的所有错误

-traditional           支持Kernighan & Ritchie C语法(如用旧式语法定义函数);如果不知道这个选项的含义,也没有关系
-IDIRECTORY      指定额外的头文件搜索路径DIRECTORY。

-LDIRECTORY      指定额外的函数库搜索路径DIRECTORY。

-DFOO=BAR 在命令行定义预处理宏FOO,其值为BAR

-IDIRNAME 将DIRNAME加入到头文件的搜索目录列表中

-LDIRNAME 将DIRNAME加入到库文件的搜索目录列表中,缺省情况下gcc 只链接共享库

-DMACRO      以字符串“1”定义 MACRO 宏。

-DMACRO=DEFN     以字符串“DEFN”定义 MACRO 宏。

-UMACRO      取消对 MACRO 宏的定义。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值