0

c ++関数を呼び出すFortran関数を含む.libライブラリファイルを作成しようとしていますが、恐ろしい「エラーLNK2019:未解決の外部シンボル...」が表示されます。コードは最終的にDLLとして他のライブラリの束でコンパイルされ、別のプログラム(PSSE)で使用されます。PSSEがライブラリを使用してDLLを作成しようとすると、コンパイルエラーが発生します。これが私が使おうとしているコードであり、その後にコンパイルコードが続きます。コードは2つの数値を足し合わせて、答えを出力する必要があります。

fort_code.f

  SUBROUTINE TESTCPP ( II, JJ, KK, LL )
  INCLUDE 'COMON4.INS'

  integer*4, external :: CPPFUNCTION

  INTEGER a, b, c, test

  IF (.NOT. IFLAG) RETURN

  a = ICON(II)
  b = ICON(II + 1)
  test = CPPFUNCTION( a , b, c )
  WRITE ( ITERM, * ) 'C = ', c
  RETURN
  END

cpp_code.cpp

extern "C" {
      void _CPPFUNCTION(int a, int b, int *c);
}

void _CPPFUNCTION(int a, int b, int *c) {
      *c = a + b;
    }

compile.bat

cl /nologo /MD /c /W3 /O2 /FD /EHsc /errorReport:prompt /D"MSWINDOWS" /D"WIN32" ^
   /D"_WINDOWS" /D"NDEBUG" "cpp_code.cpp"

IFORT /nologo /Od /Oy- /assume:buffered_io /traceback /libs:dll /threads /c /Qip ^
      /extend_source:132 /noaltparam /fpscomp:logicals /warn:nodeclarations ^
      /warn:unused /warn:truncated_source /Qauto /Op /iface:cvf /define:DLLI ^
      /include:"C:\Program Files (x86)\PTI\PSSE32\PSSLIB" ^
      /object:"fort_code.OBJ" ^
      "fort_code.f" 

lib /out:fort_cpp.lib fort_code.obj cpp_code.obj

PSSEプログラムがDLLを作成しようとすると、次のようになります。

 ifort /nologo /assume:buffered_io /traceback /libs:dll /threads /c /Qip /extend_source:132 /noaltparam /fpscomp:logicals /Qprec /warn:declarations /warn:unused /warn:truncated_source /Qauto /fp:source /iface:cvf /define:DLLI /include:"C:\Program Files (x86)\PTI\PSSE32\PSSLIB" /object:"C:\temp\INIT_620289\11hw2ap_conec.obj" /module:"C:\temp\INIT_620289" "11hw2ap_conec.f"


 ifort /nologo /assume:buffered_io /traceback /libs:dll /threads /c /Qip /extend_source:132 /noaltparam /fpscomp:logicals /Qprec /warn:declarations /warn:unused /warn:truncated_source /Qauto /fp:source /iface:cvf /define:DLLI /include:"C:\Program Files (x86)\PTI\PSSE32\PSSLIB" /object:"C:\temp\INIT_620289\11hw2ap_conet.obj" /module:"C:\temp\INIT_620289" "11hw2ap_conet.f"


 link /INCREMENTAL:NO /NOLOGO /DLL /SUBSYSTEM:WINDOWS /MACHINE:X86 /ERRORREPORT:PROMPT @"C:\temp\INIT_620289\linkfilestod9p1.txt" /OUT:"C:\temp\INIT_620289\11hw2ap_dsusr.dll" /map:"C:\temp\INIT_620289\11hw2ap_dsusr.map"

 fort_cpp.lib(fort_code.obj) : error LNK2019: unresolved external symbol _CPPFUNCTION@12 referenced in function _TESTCPP
 C:\temp\INIT_620289\11hw2ap_dsusr.dll : fatal error LNK1120: 1 unresolved externals

 ERROR during link(1)... Aborted

conec / conetは、外部ライブラリ関数への単純なFortran呼び出しです。

      SUBROUTINE CONEC
C
      INCLUDE 'COMON4.INS'
C
      CALL TESTCPP         ( 55791,     0,     0,     0)
C
      RETURN
      END
      SUBROUTINE CONET
C
      INCLUDE 'COMON4.INS'
C
      IF (.NOT. IFLAG) GO TO 9000
C
C  NETWORK MONITORING MODELS
C
C
 9000 CONTINUE
C
      RETURN
      END

Fortranからc++関数を呼び出すいくつかの異なる例を見てきましたが、それらはすべてわずかに異なって見えます。私が気づいたことの1つは_、c++関数名の前後で使用法が異なることでした。_CPPFUNCTION、、、またはを使用する方法を知るにはどうすればよいですCPPFUNCTIONCPPFUNCTION_。を使用して関数をC++でエクスポートする必要があり__declspec( dllexport )ますか?ALIAS:'_CPPFUNCTION'Fortranコードでを作成する必要がありますか?

私は次のコンパイラを使用しています:ifort:IVF IA-32 v12.1.0.233 cl:v16.00.30319.01 x86

C ++コードをFortran関数に適切にリンクするために欠けているものはありますか?

4

1 に答える 1

1

問題は、多くのオプションがあることです。なし、前後に 1 つまたは 2 つのアンダースコア、変数の後またはリストの末尾の文字列の長さ、値による呼び出しまたは参照による呼び出し。大文字、小文字、または元の命名。これらのオプションだけで、正しく動作する確率はすでに 100 分の 1 未満です (1/3*1/3*1/2*1/2*1/3)。

dumpbinユーティリティを使用して .lib ファイルをイントロスペクトし、intel fortran のデフォルト設定とプロジェクト ファイルの設定を手動でチェックすることで、これを少し減らすことができます。

いくつかの提案のように、最も洗練された方法は、bind(C)iso_c_bindingモジュールを組み合わせて使用​​することです。このbind(C)ステートメントにより、名前マングリングを知る必要がなくなります。は、C との型の互換性を確保する代わりに、c 文字列iso_c_bindings提供します。fortran はデフォルトで参照によって呼び出され、値による呼び出しに使用できることを知っておく必要があります。これにより、成功率が 1 まで上昇するはずです。integer(c_int)integer*4, value

これは、以下の c++ で定義された add1 関数を呼び出す方法の簡単な例です。

test.f90

  program example

    use iso_c_binding
    implicit none

    interface
       integer(c_int) function add1(x) bind(C,name="add1")
         !DEC$ ATTRIBUTES DLLEXPORT :: add1
         use iso_c_binding
         integer(c_int), value :: x
       end function add1
    end interface

    call callingadd1()
  contains
    subroutine callingadd1()
      write(*,*) '1+1=', add1(1)
    end subroutine callingadd1
  end program example

add1.cpp

extern "C" {
  int add1(int x);
}

int add1(int x) {
  return(x+1);
}

サブルーチンのみで例を編集します。共有オブジェクト/dll/dylib に含めるため。

subroutineonly.f90

subroutine callingadd1() bind(C, name="callingadd1")
  !DEC$ ATTRIBUTES DLLEXPORT :: callingadd1
  use iso_c_binding
  implicit none
  interface
     integer(c_int) function add1(x) bind(C,name="add1")
       !DEC$ ATTRIBUTES DLLEXPORT :: add1
       use iso_c_binding
       integer(c_int), value :: x
     end function add1
  end interface
  write(*,*) '1+1=', add1(1)
end subroutine callingadd1
于 2013-01-29T21:32:00.853 に答える