はじめに
Qiita初投稿です,はじめまして.畑山と申します.最近は趣味でFortranを使ってレイトレーシングのプログラムを書いています.
Fortranは(筆者にとっては)書きやすい言語であり,しかも高速な実行ファイルを吐き出してくれます.また,GNU Fortran(gfortran)が無料で使用できるため,環境を容易に整えられます.しかし,Fortran自体はプロットや画像表示などの可視化機能は有していません.テキストファイルに結果を書き出し,gnuplotで可視化させるといった手段などが一般的に用いられますが,ここではC#と連携させます.
Fortranで書かれた関数のコードからDLLを作成する方法,作成したDLLをC#のプログラム中で使用する方法をいろいろ調べたり試したりしたので解説します.(主にFortran-C#間の連携方法の解説を行い,可視化の具体的な方法は解説しません.)
使用環境
- Windows10 Home
- GNU Fortran 8.1.0 (MinGW-w64 4.3.5)
- visual C# 7.3
MinGWを使用することでWindowsでもgfortranを使うことができます.ここでは,64bitに対応したMinGW-w64を使用します.
DLLの作成
1. Fortranコードの記述
整数の引数に2を足した値を戻り値として返す関数のFortranコードが書かれたファイルを示します.
modulefortimplicitnonecontainsfunctionfunctionPlus2(varIn)result(varOut)implicitnoneinteger(8),intent(in)::varIninteger(8)::varOutvarOut=varIn+2endfunctionendmodule gfortranを使用する場合,Fortranコードに特別な構文や宣言は必要ありません.
モジュールを使用していますが,モジュールを使用せずに関数のみをファイル中に記述することもできます.その場合,DLL内での関数名に違いが出ます(後述).本記事ではモジュールを使用する方法をメインとしますが,使用しない場合についても解説します.
2. Fortranコードのコンパイル
コンパイルに使用するコマンドを示します.
gfortran fort.f90 -o Fdll.dll -shared
fort.f90はFortranコードのファイル名,-o Fdll.dllは作成されるファイル名を指定するためのオプション及び作成されるファイル名です.
コンパイル時にオプション-sharedをつけることで,DLLが作成されます.
3. コンパイル結果の確認
作成されたFdll.dllをDependency Walkerを用いて確認します.
関数名が__fort_MOD_functionplus2になりました.DLLにおける関数名は次のような法則で決定されるようです.
__モジュール名_MOD_関数名- モジュール名,関数名は全て小文字になる
また,モジュールを使用しない場合,関数名は関数名(小文字)_になります.
C#コード中でのDLLの使用
1. C#コードの記述
DLLを用いて1+2を計算するためのC#コードが書かれたファイルを示します.
usingSystem;usingSystem.Runtime.InteropServices;namespaceFtoCsharp{classProgram{[DllImport("./../../../fortran/fdll.dll",EntryPoint="__fort_MOD_functionplus2")]publicstaticexternlongFunctionPlus2(reflongvarIn);staticvoidMain(string[]args){longa=1,b;b=FunctionPlus2(refa);Console.Write(a);Console.Write("+2 = ");Console.Write(b);Console.Read();}}}// 実行結果// 1+2 = 3[DllImport("dllファイル名",EntryPoint="関数名")] System.Runtime.InteropServices.DllImportを使用することでDLL内の関数を呼び出せるようになります.引数としてDLLのファイル名とDLL内での関数名を渡します.
publicstaticexternlongFunctionPlus2(reflongvarIn); C#中での関数の名称,引数,戻り値の型などを設定しています.
関数の名称は任意の名前に設定できます.引数,戻り値の型はFortranコード内での宣言integer(8)に対応する型であるlong型に設定しています.引数はrefを用いて参照渡しに設定しなくてはいけないようです.
2. C#コードのビルド
DLLのbit数とC#側のbit数を統一する必要があります.本記事ではDLLを64bitで作成しました.C#側も構成マネージャーから64bitにします.あとは通常のビルドと同様です.
まとめ
- コンパイルオプションは
-shared - dll内での関数名は
__モジュール名(小文字)_MOD_関数名(小文字) System.Runtime.InteropServices.DllImportを使ってC#側から呼び出す- 引数は参照渡しにする
次回予告
DLLの作成法,C#側からの呼び方についての解説は以上です.本記事では整数型を扱う関数を例文にしました.次の記事では,他の型の場合やサブルーチンの場合の注意点について解説する予定です.