ライブラリの管理(静的および動的ライブラリ)#
数十個のソースファイルで構成されるプログラム(よくあることです!)を管理する必要がある場合、すべてのオブジェクトファイルを指定するために必要なコマンドラインは非常に長くなります。これはすぐに面倒になり、維持できなくなる可能性があります。そのため、別の解決策が必要です。独自のライブラリを作成します。
ライブラリには、コンパクトな形式で任意の数のオブジェクトファイルが含まれているため、コマンドラインがはるかに短くなります。
$ gfortran -o tabulate tabulate.f90 functions.o supportlib.a
ここで、「supportlib.a」は、コンパイルされてライブラリに格納された1つ、2つ、または多くのオブジェクトファイルのコレクションです。拡張子「.a」は、LinuxおよびLinuxライクなプラットフォームで使用されます。Windowsでは、拡張子「.lib」が使用されます。
独自のライブラリを作成するのはそれほど複雑ではありません。Linuxでは、ar
のようなユーティリティを使用してこれを実現できます。
$ gfortran -c file1.f90 file2.f90
$ gfortran -c file3.f90 ...
$ ar r supportlib.a file1.o file2.o
$ ar r supportlib.a file3.o ...
または、Windowsではlib
ユーティリティを使用します。
c:\...> ifort -c file1.f90 file2.f90
c:\...> ifort -c file3.f90 ...
c:\...> lib /out:supportlib.lib file1.obj file2.obj
c:\...> lib supportlib.lib file3.obj ...
注記
ar
コマンドにr
オプションを指定すると、ライブラリが作成されるか(名前はオプションの後に表示されます)、新しいオブジェクトファイルがライブラリに追加されるか(または既存のファイルが置き換えられます)。lib
コマンドでは、/out:
オプションとその横に新しいライブラリの名前を指定すると、新しいライブラリが作成されます。既存のライブラリにオブジェクトファイルを追加するには、/out:
部分を省略します。Linuxのようなプラットフォームでは、ライブラリに名前を付ける特定の規則があります。ライブラリに「libname.a」(「lib」プレフィックスに注意)という名前を付ける場合、リンクステップで
-lname
として参照できます。ライブラリは、多くの場合、
-L
または/LIBPATH
オプションで示されるディレクトリで検索されます。これにより、すべてのライブラリの正確なパスを指定する必要がなくなります。
ライブラリを使用すると、非常に長いコマンドラインに頼ることなく、非常に大きなプログラムをビルドできます。
静的ライブラリと動的ライブラリ#
上記の議論では、いわゆる静的ライブラリを使用していることを暗黙的に仮定しています。静的ライブラリ(または少なくともその内容の一部)は、実行可能プログラムの不可欠な一部になります。プログラムに組み込まれたルーチンを変更する唯一の方法は、新しいバージョンのライブラリを使用してプログラムを再ビルドすることです。
柔軟な代替手段として、いわゆる動的ライブラリを使用できます。これらのライブラリは実行可能プログラムの外に残るため、プログラム全体を再ビルドせずに置き換えることができます。コンパイラ、そして実際にはオペレーティングシステム自体も、このような動的ライブラリに大きく依存しています。動的ライブラリは、実行するために少しの助けが必要な実行可能プログラムの一種と考えることができます。
動的ライブラリのビルド方法は、静的ライブラリのビルド方法とは少し異なります。ar
やlib
などのツールではなく、コンパイラ/リンカを使用します。
Linuxの場合
$ gfortran -fpic -c file1.f90 file2.f90
$ gfortran -fpic -c file3.f90 ...
$ gfortran -shared -o supportlib.so file1.o file2.o file3.o ...
Windowsの場合(Intel Fortran コンパイラを使用)
$ ifort -c file1.f90 file2.f90
$ ifort -c file3.f90 ...
$ ifort -dll -exe:supportlib.dll file1.obj file2.obj file3.obj ...
違いは次のとおりです。
Linuxでは、オブジェクトコードがわずかに異なるため、コンパイルオプション(gfortranの場合は
-fpic
)を指定する必要があります。リンクステップで、動的ライブラリ(Linux:共有オブジェクト/ライブラリ、そのため拡張子は「.so」です。Windows:ダイナミックリンクライブラリ)を希望することを伝える必要があります。
さらに注意すべきことが1つあります。Windowsでは、プロシージャがエクスポートされる、つまり動的ライブラリで表示可能になるように明示的に指定する必要があります。これを実現する方法は、使用するコンパイラに応じていくつかあります。1つの方法は、いわゆるコンパイラディレクティブを使用することです。
subroutine myroutine( ... )
!GCC$ ATTRIBUTES DLLEXPORT:: myroutine
または、Intel Fortran コンパイラを使用する場合
subroutine myroutine( ... )
!DEC$ ATTRIBUTES DLLEXPORT:: myroutine
動的ライブラリ(DLL)に加えて、いわゆるインポートライブラリが生成される場合があります。
詳細がコンパイラによって異なるため、Cygwin の gfortran と Windows の Intel Fortran の2つの例を示します。どちらの場合も、「tabulate.f90」ファイルのtabulate
プログラムを見ていきます。
GNU/Linux と gfortran#
tabulate
プログラムは、ユーザー定義ルーチンf
を必要とします。これを動的ライブラリ(「functions.dll」など)に配置する場合、別の動的ライブラリをディレクトリに配置することで、関数の実装を簡単に置き換えることができます。プログラム自体を再ビルドする必要はありません。
Cygwinでは、プロシージャを明示的にエクスポートする必要はありません。動的ライブラリをビルドすると、公開されているすべてのルーチンがエクスポートされます。また、インポートライブラリも生成されません。
動的ライブラリは単一のソースファイルからビルドできるため、ショートカットを使用できます。
$ gfortran -shared -o functions.dll functions.f90
これにより、「functions.dll」と「user_functions.mod」ファイルが生成されます。nm
ユーティリティは、関数f
の正確な名前を教えてくれます。
$ nm functions.dll
...
000000054f9d7000 B __dynamically_loaded
U __end__
0000000000000200 A __file_alignment__
000000054f9d1030 T __function_MOD_f
000000054f9d1020 T __gcc_deregister_frame
000000054f9d1000 T __gcc_register_frame
...
他のモジュールで定義されている可能性のある他のルーチン「f」と区別するために、プレフィックス__function_MOD_
が付けられています。
次のステップは、プログラムをビルドすることです。
$ gfortran -o tabulate tabulate.f90 functions.dll
DLL と .mod ファイルを使用して、関数のインターフェース、正しい名前、および「functions.dll」と呼ばれる DLL への参照に関するチェックを行いながら、実行可能プログラムをビルドします。
共有ライブラリ「functions.dll」を別のものと置き換えることができますが、正しいインターフェースを使用する必要があることに注意してください。コンパイラ/リンカはもはや呼び出されないので、チェックを行うことができません。
Windows と Intel Fortran#
設定はLinuxと同じですが、Windowsではルーチンを明示的にエクスポートする必要があります。そして、インポートライブラリが生成されます。これは、リンクステップで使用されるライブラリです。
ソースファイルにはコンパイラディレクティブを含める必要があります。それ以外の場合は、関数f
はエクスポートされません。
real function f( x )
!DEC$ ATTRIBUTES DLLEXPORT :: f
再びショートカットを使用します。
$ ifort -exe:functions.dll functions.f90 -dll
これにより、「functions.dll」、「user_functions.mod」、および「functions.lib」(およびここでは重要ではない他の2つのファイル)が生成されます。「依存関係ウォーカー」プログラムは、関数「f」の正確な名前がFUNCTION_mp_F
であることを示しています。また、エクスポートされるため、次のステップでリンカによって検出できます。
$ ifort tabulate.f90 functions.lib
エクスポートライブラリの名前を指定する必要があり、DLLではないことに注意してください!
(また、Intel Fortran コンパイラは、実行可能ファイルの名前として最初のソースファイルの名前を使用します。ここでは-exe
オプションを使用しません。)
Cygwin と同様に、DLL と .mod ファイルを使用して、関数のインターフェース、正しい名前、および「functions.dll」と呼ばれる DLL への参照に関するチェックを行いながら、実行可能プログラムをビルドします。
共有ライブラリ「functions.dll」を別のものと置き換えることができますが、同じ注意が必要です。実装は非常に異なる可能性がありますが、関数のインターフェースは同じでなければなりません。