静的ライブラリは、実行可能ファイルをビルドするときに使うことができる、コンパイル済みコードです。
コンパイラが、実行可能ファイルを作るときに、基本のソースファイルは、最初に、オブジェクト・ファイルに変換されます。
そのとき、オブジェクト・ファイルは、実行可能ファイルを作るために、一緒に結合されます。
ソースコードをコンパイルするとき、必ずしもひとつの実行可能ファイルにする必要は、ありません。
代わりに、私たちは、オブジェクト・ファイル(ソースから、作られる)のすべてを、静的ライブラリと呼ばれる一つのファイルに、集めます。
ライブラリは、静的と呼ばれます。というのは、ライブラリが含んでいるオブジェクト・ファイルは、後に実行可能ファイルに結合されるとき、ライブラリの必要なすべてのコードのコピーが、実行可能ファイルに加えられるからです。
言い換えると、ライブラリを変更した場合は、そのオブジェクトを、実行可能ファイルに結合し直すために、再度、コンパイルする必要が有ります。
一度、ライブラリを作っておくと、私たちは、ライブラリが含むコードを、まるで直接私たちのプログラムでソースをコンパイルしているように、使うことができます。
静的ライブラリとの変数の交換/共有
静的ライブラリでは、ライブラリ・コードとモジュール・コードの両方で、
Common か
Extern キーワードを使って変数を直接共有できます。
その他、ライブラリ手続きにパラメータを(値または参照)渡したり、ライブラリ関数から変数を(値または参照)返すことで、間接的に共有ライブラリとデータ交換(値で)したり、データ共有(参照で)したりできます。
静的ライブラリの簡単な例
下は、これらの3個のファイルを使って、静的なライブラリを生成する、簡単な例です:
- mylib1.bas - ライブラリのためのソース → libmylib1.a
- mylib1.bi - ライブラリのためのヘッダー
- mytest1.bas - テスト・プログラム → mytest1.exe
この簡単な事例で作成するライブラリは、ただ一つの関数を提供する、ただ一つのモジュールです:
'' mylib1.bas
'' 右のようにコンパイルしてください:
fbc -lib mylib1.bas
'' 2つの数字を合計して、結果を返します
Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
Return( x + y )
End Function
下のように、ライブラリをコンパイルします:
fbc -lib mylib1.bas
注意:FbEdit を使う場合は、オプションのリストから「Library」を選択します。
-lib オプションを指定すると、コンパイラは、ソースコード
mylib1.bas をとって、ソースコードを、オブジェクト・ファイル
mylib1.o に入れます。次に、保存記録とも呼ばれる、ライブラリ・ファイル
libmylib1.a にオブジェクト・ファイルを蓄えます。
一般に、ライブラリは、多くのモジュール(ソースファイル)を、それぞれ多くの関数とともに含めることができます。しかし、この簡単な例では、それぞれ1つだけです。
他のソースコードで、ライブラリを利用するために、ライブラリにいったい何があるかを、コンパイラに伝える手段が必要です。
このための方法として、ヘッダーファイルに、ライブラリへの宣言 (インタフェースとか、API と呼ばれます) を置きます。
'' mylib1.bi
#inclib "mylib1"
Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer
ヘッダーは、コンパイルする必要ありません。
他のソース・ファイルに含めることができるように、ヘッダーは、ソースの形式です。
#inclib 命令文は、私たちが、最終的に実行可能を作るときに結合する必要がある、静的ライブラリの名前を、コンパイラに伝えます。
私たちのライブラリ (.a ファイル) と、ヘッダー (.bi ファイル) を、テスト・プログラムで、試すことができます:
'' mytest1.bas
''
右のようにコンパイルしてください:
fbc mytest1.bas
#include once "mylib1.bi"
Print Add2
(1,2)
Sleep
#include 命令文は、
mylib.bi から、ソースコードを含めるように、コンパイラに伝えます。これは、まさしく、元のソースに、
mylib.bi の内容をタイプしたかのようになります。
私たちが、インクルード・ファイルを書いた通りに、インクルードファイルは、ライブラリについて知る必要があるすべてを、コンパイラに伝えます。
これを、下のように、コンパイルします:
fbc mytest1.bas
そして、実行可能ファイル
mytest を実行すると、下の結果が表示されるでしょう。
3
OOP 静的ライブラリの高度な例
以下は、これらの3つのファイルを使って OOP 静的ライブラリを作成する高度な例です:
- varZstring.bi - ライブラリのヘッダー
- varZstring.bas - ライブラリのソース
- varZstringTest.bas - テスト・プログラム
上記と同様の方法でライブラリをコンパイルしてから、テスト・プログラムをコンパイルして実行します。
ライブラリのヘッダーファイル:
'' header file: 'varZstring.bi'
Type varZstring Extends ZString
Public:
Declare Constructor (ByRef z As Const ZString)
Declare Operator Cast () ByRef As ZString
Declare Operator Let (ByRef z As Const ZString)
Declare Property allocated () As Integer
Declare Destructor ()
Private:
Dim As ZString Ptr _p
Dim As UInteger _allocated
End Type
Declare Operator Len (ByRef v As varZstring) As Integer '' mandatory for the user code to call
'' the overload Len operator and
'' not the prebuilt-in Len operator
注: 各多重定義手続きも合わせて宣言するように、注意してください。ユーザー・コードでの使用が、事前に組み込まれた手続きと構文的に互換性がある場合、宣言がなくても必ずしもコンパイル・エラーが発生するわけではないからです。しかし、結果は明らかに期待どおりではありません。
ライブラリのソースファイル:
'' library module: 'varZstring.bas'
#include "varZstring.bi"
Constructor varZstring (ByRef z As Const ZString)
If This._p <> 0 Then
Deallocate(This._p)
End If
This._allocated = Len(z) + 1
This._p = CAllocate(This._allocated, SizeOf(ZString))
*This._p = z
End Constructor
Operator varZstring.Cast () ByRef As ZString
Return *This._p
End Operator
Operator varZstring.Let (ByRef z As Const ZString)
If This._allocated < Len(z) + 1 Then
Deallocate(This._p)
This._allocated = Len(z) + 1
This._p = CAllocate(This._allocated, SizeOf(ZString))
End If
*This._p = z
End Operator
Property varZstring.allocated () As Integer
Return This._allocated
End Property
Destructor varZstring ()
Deallocate(This._p)
This._p = 0
End Destructor
Operator Len (ByRef v As varZstring) As Integer
Return Len(Type<String>(v)) '' found nothing better than this
End Operator '' (or: 'Return Len(Str(v))')
テスト・プログラムファイル:
'' test program: 'varZstringTest.bas'
#include "varZstring.bi" '' must contain also the overload Len operator declaration,
'' otherwise the prebuilt-in Len operator is called and applied
'' on the object variable (providing the length of its member data)
#inclib "varZstring" '' one can also put this line in the 'varZstring.bi' file
'' (and not in this file), but it seems a bit crooked
Print "VARIABLE",,, "| LEN| SIZEOF|"
Print "------------------------------------------|--------|--------|"
Dim As varZstring v = "FreeBASIC" '' adjusts memory allocation to minimum
Print "varZstring v:", "'" & v & "'",, "|"; Using "########|"; Len(v); v.allocated
Dim As ZString * 256 z
z = v
Print "Zstring z:", "'" & z & "'",, "|"; Using "########|"; Len(z); SizeOf(z)
v = z & " & SourceForge" '' only increases memory allocation if necessazy
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
v = z & " & Wiki" '' only increases memory allocation if necessazy
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
v.Constructor(v) '' readjusts memory allocation to minimum
Print "varZstring v:", "'" & v & "'", "|"; Using "########|"; Len(v); v.allocated
Sleep
出力:
VARIABLE | LEN| SIZEOF|
------------------------------------------|--------|--------|
varZstring v: 'FreeBASIC' | 9| 10|
Zstring z: 'FreeBASIC' | 9| 256|
varZstring v: 'FreeBASIC & SourceForge' | 23| 24|
varZstring v: 'FreeBASIC & Wiki' | 16| 24|
varZstring v: 'FreeBASIC & Wiki' | 16| 17|
ライブラリを作るとき、複数のソース・モジュールを使用できます。
そして、基本プログラムは、それぞれの必要なヘッダーを含めることで、複数のライブラリを使用できます。
ライブラリには、いくつものヘッダーを使用する、とても大きなものもあります。
非常に大きいプロジェクトでは、めったに変わらないいくつかのコード・モジュールを、ライブラリに作っておくと、コンパイル時間を、劇的に改善することができます。
ライブラリは、任意で、
-g コマンドライン・オプションを指定することで、デバッグ情報を含めることができます。
ライブラリは、オプションとして、モジュール構築子、メインコード、モジュール解体子を含めることができます。
モジュール構築子、次にメインコードの順にライブラリのロード時に実行されます。モジュール解体子はライブラリのアンロード時に実行されます。
オブジェクトファイルは、したがってライブラリは、プラットホーム特定で、いくつかの場合、コンパイラのバージョンと、FreeBASIC ランタイム・ライブラリに、特定です。
参照: