静的ライブラリファイルは、ar(1) ユーティリティーを使用して、すでにコンパイルされたオブジェクトファイル (. o ファイル) から構築します。
リンカーは、リンクするプログラム中で参照される入口を持つ要素をライブラリから抽出します。 たとえば、副プログラム、入口名、BLOCKDATA 副プログラム中で初期化される COMMON ブロックなどです。これらの抽出された要素 (ルーチン) は、リンカーによって生成される a.out 実行可能ファイルに恒久的にリンクされます。
静的ライブラリとリンクには、動的なライブラリとリンクと比較した場合、主に 3 つの問題に注意しなければいけません。
静的ライブラリは自己依存性 (独立性) に優れていますが、適用性に劣ります。
a.out 実行可能ファイルを静的にリンクすると、必要なライブラリルーチンは実行可能バイナリファイルの一部となります。しかし、a.out 実行可能ファイルにリンクされた静的ライブラリルーチンを更新する必要が出てきた場合 a.out ファイル全体をリンクし、生成し直さなければ、更新されたライブラリを利用することができません。動的ライブラリを使用すれば、ライブラリは a.out ファイルの一部とはならず、リンクは実行時に行われます。更新された動的ライブラリを利用するために必要なことは、新しいライブラリをシステムにインストールするだけです。
静的ライブラリの「要素」は個々のコンパイル単位 .o ファイルです。
1 つのコンパイル単位 (ソースファイル) には複数の副プログラムが含まれている場合があるので、いっしょにコンパイルすると、これらのルーチンは静的ライブラリ中の 1 つのモジュールとなります。つまり、コンパイル単位中のすべてのルーチンがいっしょに a.out 実行可能ファイルに読み込まれるが、実際に呼び出されるのはこれら副プログラムの 1 つだけであるということを意味します。この状況は、複数のライブラリルーチンを複数のコンパイル可能ソースファイルに分散するという最適化によって改良できます。ただし、プログラムによって実際に参照されるライブラリモジュールだけが実行可能ファイルに読み込まれます。
静的ライブラリのリンクでは、リンクの順序が重要です。
リンカーは、コマンド行に現れる順番、すなわち左から右に入力ファイルを処理します。リンカーがライブラリの要素を読み込むべきかどうかは、すでに処理されたライブラリの要素によって決定されます。この順番は、要素がライブラリファイル中で現れる順番に依存するだけでなく、コンパイルコマンド行上で指定されたライブラリの順番にも依存します。
例: Fortran プログラムが main.f と crunch.f の 2 つのファイルに記述され、crunch.f だけがライブラリにアクセスする場合、crunch.f または crunch.o より前にライブラリを参照するとエラーになります。
demo% f95 main.f -lmylibrary crunch.f -o myprog |
(誤)
demo% f95 main.f crunch.f -lmylibrary -o myprog |
(正)
1 つのプログラムのルーチンすべてがいくつかのソースファイルのグループに分散されており、また、これらのソースファイルすべてがサブディレクトリ test_lib/ にあるものと仮定します。
さらに、それぞれのファイルがユーザーのプログラムによって呼び出される 1 つの副プログラムと、その副プログラムからは呼び出されるがライブラリ中のほかのルーチンからは呼び出されない「ヘルパー」ルーチンを持つように、ファイルを編成すると仮定します。また、複数のライブラリルーチンから呼び出されるヘルパールーチンはすべて 1 つのソースファイルにまとめられているとします。これによって、合理的に上手に編成されたソースファイルとオブジェクトファイルのセットができます。
各ソースファイルの名前は、そのファイルの中の最初のルーチンの名前から決定すると仮定します。ほとんどの場合、それはライブラリ中の主要なファイルです。
demo% cd test_lib demo% ls total 14 2 dropx.f 2 evalx.f 2 markx.f 2 delte.f 2 etc.f 2 linkz.f 2 point.f |
低レベルの「ヘルパー」ルーチンはすべてファイル etc.f にまとめられます。ほかのファイルには、1 つまたは複数の副プログラムが入ります。
まず、-c オプションを使用して、各ライブラリソースファイルをコンパイルし、対応する再配置可能な .o ファイルを生成します。
demo% f95 -c *.f demo% ls total 42 2 dropx.f 4 etc.o 2 linkz.f 4 markx.o 2 delte.f 4 dropx.o 2 evalx.f 4 linkz.o 2 point.f 4 delte.o 2 etc.f 4 evalx.o 2 markx.f 4 point.o demo% |
次に、 ar を使用して、静的ライブラリ testlib.a を作成します。
demo% ar cr testlib.a *.o |
このライブラリを使用するためには、コンパイルコマンド上にライブラリファイルを指定するか、-l と -L コンパイルオプションを使用します。次の例では .a ファイルを直接使用します。
demo% cat trylib.f C testlib ルーチン群をテストするためのプログラム x=21.998 call evalx(x) call point(x) print*, ’value ’,x end demo% f95 -o trylib trylib.f test_lib/testlib.a demo% |
主プログラムがライブラリ中の 2 つのルーチンだけを呼び出しているところに注目してください。ライブラリ中の呼び出されないルーチンが実行可能ファイルに読み込まれていないことを確認するには、nm によって表示される実行可能ファイル中の名前のリストで調べます。
demo% nm trylib | grep FUNC | grep point [146] | 70016| 152|FUNC |GLOB |0 |8 |point_ demo% nm trylib | grep FUNC | grep evalx [165] | 69848| 152|FUNC |GLOB |0 |8 |evalx_ demo% nm trylib | grep FUNC | grep delte demo% nm trylib | grep FUNC | grep markx demo% ..etc |
前述の例では、grep は名前のリストから、実際に呼び出されたライブラリルーチンの項目だけを見つけます。
ライブラリを参照するもう 1 つの方法は、-llibrary と -Lpath オプションを使用する方法です。ここでは、libname.a の規則に従うため、ライブラリの名前を変更しなければいけません。
demo% mv test_lib/testlib.a test_lib/libtestlib.a demo% f95 -o trylib trylib.f -Ltest_lib -ltestlib |
-llibrary と -Lpath オプションは、ほかのユーザーが参照できるように、/usr/local/lib のようなシステム上の一般的にアクセス可能なディレクトリにインストールされたライブラリに使用できます。たとえば、 libtestlib.a を /usr/local/lib に置いた場合、次のコマンドを使用してコンパイルするよう、ほかのユーザーに知らせてください。
demo% f95 -o myprog myprog.f -L/usr/local/lib -ltestlib |
2、3 の要素だけをコンパイルし直す場合、ライブラリ全体をコンパイルし直す必要はありません。ar の -r オプションを使用すると、静的ライブラリ中の個々の要素を置換できます。
例: 静的ライブラリ中の 1 つのルーチンをコンパイルし直し、置換します。
demo% f95 -c point.f demo% ar -r testlib.a point.o |
ar を使用して構築しているときに静的ライブラリ中の要素を整列するには、コマンド lorder(1) と tsort(1) を使用します。
demo% ar -cr mylib.a 'lorder exg.o fofx.o diffz.o | tsort' |