1. 程式人生 > >fortran和c++互操作

fortran和c++互操作

fortran程式,編譯成lib,c++呼叫,總是出現連結錯誤。可能的原因:

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 visual fortran 2013

fortran程式編譯後,函式名預設是大寫,後面不帶下劃線。比如_A()

這時,在c程式裡面的宣告顯然要據此做修改。比如extern "C" A();呼叫形式:A()。

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++:


 
  
   
    
01 extern "C"
02  
03 double pt_h_gas(double p ,double t,float SO2,float H2O,float CO2,float N2,float O2,
04 float Ar,float He,float unit);
05  
06 #include "stdafx.h"
07  
08 int _tmain(int argc, _TCHAR* argv[])
09 {
10 float SO2 , H2O, CO2, N2, O2,Ar,He, unit;
11 double enthalpy;
12 double p,t;
13 enthalpy = pt_h_gas (p ,t,SO2,H2O,CO2,N2,O2,Ar, He,unit);
14 }

and this for the Fortran:


 
  
   
    view source
    print
    
1 Function pt_h_gas(p , t, y1, y2, y3, y4, y5, y6, y7,unit) bind(C)
2  
3 use iso_c_binding
4  
5 real(C_DOUBLE) :: pt_h_gas
6 real(C_FLOAT), value:: y1, y2, y3, y4, y5, y6, y7, unit
7 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�

                   encesin identifiers and to preserve the case of

                   externalnames.

 

               � -names lowercase

 

                   Causesthe compiler to ignore case differences in

                   identifiersand to convert external names to low�

                   ercase.     This is the default.

 

               � -names uppercase

 

                   Causesthe compiler to ignore case differences in

                   identifiersand 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 areconventions 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.


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

ifconsol.lib問題,需要新增ivf編譯器Lib檔案目錄,然後新增ifconsol.lib,然後還要將程式碼生成選項改為多執行緒除錯。


3 備忘

檢視符號表: objdump -t xxx.so 。-T 和 -t 選項在於 -T 只能檢視動態符號,如庫匯出的函式和引用其他庫的函式,而 -t 可以檢視所有的符號,包括資料段的符號