FreeBASIC マニュアルのトップに戻る

FreeBASIC ProPgSharedLibraries

目次→教本→プログラマーのための案内Shared Libraries←オリジナル・サイト

共有ライブラリ(DLL) 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

←リンク元に戻る プログラム開発関連に戻る

共有ライブラリは、コンパイルされたコードで、実行可能ファイルを走らせるとき、ロードされ、後で使われることができます。

コンパイラが、実行可能ファイルを作るときに、最初に、基本のソースファイルが、オブジェクト・ファイルに変換されます。
関係するオブジェクト・ファイルは、実行ファイルを作るために、一緒に結合されます。
共有ライブラリが、共有ライブラリの中にオブジェクト・ファイルを含むという点で、静的ライブラリに、似ています。
しかし、共有ライブラリは、実行可能ファイルが走るときだけ、共有ライブラリがロードされる点で、実行可能ファイルにも似ています。

このライブラリは、「共有」と呼ばれます。というのは、ライブラリのコードは、実行時に、実行可能ファイルによって、ロードされますが、複数の実行可能ファイルによって同時にロードされることもできます。このとき、共有ライブラリは、一つあるだけでよいのです。

一度、ライブラリを作っておけば、次に、私たちは、まるでまさしく直接私たちのプログラムで、ライブラリが含むコードのソースをコンパイルしているように、使用できます。

目次:
0. 共有ライブラリと変数を共有
1. 共有ライブラリの例
2. Windows で共有ライブラリを使う
3. リナックスで共有ライブラリを使う
Using Shared Libraries on DOS => see its own page:Shared Libraries - DOS
4. シンボルをエクスポートする実行ファイル
5. 動的に共有ライブラリをロードする
6. Windows での共有ライブラリとの変数の交換/共有
7. Windows での定義ファイルからのインポート ライブラリの作成、または DLL ファイルからのインポート ライブラリまたは定義ファイルの作成


0. 共有ライブラリと変数を共有
共有ライブラリでは、CommonExtern キーワードを使って変数を直接共有することはできません。
それ以外では、ライブラリ手続きにパラメータ(値または参照)を渡したり、ライブラリ関数から変数(値または参照)を返すことで、共有ライブラリと間接的にデータを交換できます。
このページの頭に戻る


1. 共有ライブラリの例
下の 3 つのファイルを使って、共有ライブラリを作成する、簡単な例を紹介します:

この例のライブラリは、一つの関数を提供する、一つのモジュールです:

'' mylib2.bas
'' 右のオプションでコンパイルします:fbc -dll mylib2.bas

'' 2つの数を合計して、結果を返します
Public Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer Export
  Return( x + y )
End Function


コンパイル・オプション ライブラリを、下のようにコンパイルしてください:
fbc -dll mylib2.bas

注意:FbEdit を使う場合は、オプションのリストから「Windows dll」を選択します。
 
-dll オプションは、コンパイラに、ソースコード mylib2.bas をとって、オブジェクトファイル mylib2.o に変換して、次に、オブジェクトファイルを、共有ライブラリに蓄えるように、伝えます。
共有ライブラリの名前は、プラットホーム依存して、linux の場合は、.so 拡張子に、Windows の場合は、.dll 拡張子に、なります。
ライブラリは、一般に、それぞれ多くの関数を持つ、多くのモジュール(ソースファイル)を含みます。しかし、この簡単な例では、モジュールと関数は、それぞれ1つだけです。

共有ライブラリを作るのは、Export 宣言指定子を追加する以外は、静的ライブラリを作るのと、ほとんど同じです。
Export は、共有ライブラリをロードする他の実行可能ファイルに、関数を見えるようにするように、コンパイラに、伝えまます。

他のソースコードでライブラリを使うためには、何がライブラリにあるかをコンパイラに伝える手段が必要です。
何がライブラリにあるかをコンパイラに伝えるために、ヘッダーファイルの、ライブラリの宣言(インタフェース、とか API と呼ばれる)があります。

'' mylib2.bi
#inclib "mylib2"
Declare Function Add2( ByVal x As Integer, ByVal y As Integer ) As Integer


ヘッダーを、コンパイルする必要は、ありません。
ヘッダーは、他のソース・ファイルに含めることができるように、ソースの形式がよいのです。
#inclib 命令文は、実行可能ファイルを走らせるときに、リンクする必要がある、共有ライブラリの名前を、コンパイラに、伝えます。

ここで作ったライブラリ(.dll/.so ファイル) と、ヘッダー(.bi ファイル) を使って、テスト・プログラムで試すことができます:

'' mytest2.bas
'' 右のように、コンパイルします:fbc mytest2.bas
#include once "mylib2.bi"
Print Add2 (1,2)
Sleep


#include 命令文は、mylib.bi からソースコードを含めるように、コンパイラに伝えます。まるで、私たちが、元のソースに、mylib.bi の内容を、タイプしたかのようになります。
インクルード・ファイルを書いた方法で、インクルード・ファイルは、ライブラリに関して知らなければならないすべてを、コンパイラに伝えます。

これを、下のようにコンパイルします:
fbc mytest2.bas

そして、mytest 実行可能ファイルを実行すると、下の結果が表示されます:

3

ライブラリを作るとき、複数のソース・モジュールを使うことができます。
そして、基本プログラムは、それぞれの必要なヘッダーを含めることによって、複数のライブラリを使用できます。
ライブラリの中には、いくつものヘッダーを使う、大きなものもあります。
非常に大きいプロジェクトでは、めったに変更しない、いくつかのコード・モジュールを、共有ライブラリとして作っておくと、コンパイル時間と、リンク時間を、劇的に減らすことができます。

共有ライブラリは、任意で、-g コマンドライン・オプションを指定するとこによって、デバッグ情報を含めるようにすることができます。

共有ライブラリには、オプションとして、モジュールコンストラクタ、メインコード、モジュールデストラクタを含めることができます。モジュールコンストラクタ、メインコードの順にライブラリロード時に実行されます。モジュールデストラクタはライブラリのアンロード時に実行されます。

オブジェクトファイル、およびしたがって、共有ライブラリは、プラットホームで固有です。そして、いくつかの場合、コンパイラのバージョンと、FreeBASIC ランタイム・ライブラリに、特定されます。
このページの頭に戻る

2. Windows で共有ライブラリを使う

Windows では、共有ライブラリ(DLL)を使う実行可能ファイルが、実行時に、共有ライブラリを見つけられる場所に、それを格納しなければなりません。

オペレーティング・システムは、以下のディレクトリを捜します:


ディレクトリを探す順番は、使用中の Windows バージョンによって異なります。そして、オペレーティング・システムが構成している設定によっても、変わります。
このページの頭に戻る

3. リナックスで共有ライブラリを使う

デフォルトで、Linux は、通常、カレントディレクトリ や、実行可能ファイルがロードされたディレクトリを、捜しません。
以下のどちらかが必要です:


実行可能ファイル ./mytest/ を走らせて、一時的にカレント・ディレクトリを捜すように linux に伝えるには、下のシェル・コマンドを使ってください:

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./mytest
このページの頭に戻る

4. シンボルをエクスポートする実行ファイル

実行可能ファイルが、共有ライブラリがロードされるとき、他の共有ライブラリに使われるシンボルを持っている場合は、Export 手続き宣言指定子を使います。そして、実行可能ファイルを作る(結合する)ときに、-export コマンドラインを使います。

-export オプションは、-dylib-dll コマンドライン・オプションと共に使う場合は、特に付加的な効果は、ありません。

このページの頭に戻る

5. 動的に共有ライブラリをロードする
共有ライブラリは、プログラムの実行時に、ライブラリとそのシンボルをロードすることによって、動的に、ロードして、使用されます。


共有ライブラリ中の手続きは、手続き定義の最初の行で Export 指定子を使って、シンボル名が、共有ライブラリのエクスポート・テーブルに配置されるようにする必要があります。

'' mydll.bas
'' compile as: fbc -dll mydll.bas
'' This will create mydll.dll (and libmydll.dll.a import library) on Windows,
'' and libmydll.so on Linux.
''
'' Note: libmydll.dll.a is an import library, it's only needed when creating
'' an executable that calls any of mydll's functions, only distribute
'' the DLL files with your apps, do not include the import libraries,
'' they are useless to end-users.

'' Simple exported function; the <alias "..."> disables FB's default
'' all-upper-case name mangling, so the DLL will export AddNumbers() instead of
'' ADDNUMBERS().
Function AddNumbers Alias "AddNumbers"( ByVal a As Integer, ByVal b As Integer ) As Integer Export
    Function = a + b
End Function



'' load.bas: Loads mydll.dll (or libmydll.so) at runtime, calls one of mydll's
'' functions and prints the result. mydll is not needed at compile time.
'' compile as: fbc test.bas
''
'' Note: The compiled mydll.dll (or libmydll.so) dynamic library is expected
'' to be available in the current directory.

'' Note we specify just "mydll" as library file name; this is to ensure
'' compatibility between Windows and Linux, where a dynamic library
'' has different file name and extension.
Dim As Any Ptr library = DyLibLoad( "mydll" )
If( library = 0 ) Then
    Print "Failed to load the mydll dynamic library, aborting program..."
    End 1
End If

'' This function pointer will be used to call the function from mydll, after
'' the address has been found. Note: It must have the same calling
'' convention and parameters.
Dim AddNumbers As Function( ByVal As Integer, ByVal As Integer ) As Integer
AddNumbers = DyLibSymbol( library, "AddNumbers" )
If( AddNumbers = 0 ) Then
    Print "Could not retrieve the AddNumbers() function's address from the mydll library, aborting program..."
    End 1
End If

Randomize Timer

Dim As Integer x = Rnd * 10
Dim As Integer y = Rnd * 10

Print x; " +"; y; " ="; AddNumbers( x, y )

'' Done with the library; the OS will automatically unload libraries loaded
'' by a process when it terminates, but we can also force unloading during
'' our program execution to save resources; this is what the next line does.
'' Remember that once you unload a previously loaded library, all the symbols
'' you got from it via dylibsymbol will become invalid, and accessing them
'' will cause the application to crash.
DyLibFree( library )


このページの頭に戻る

6. Windows での共有ライブラリとの変数の交換/共有
Windows は、変数を共有ライブラリと直接共有するための Common または Extern キーワードをサポートしていません。
それ以外の場合(任意のプラットフォームで動作)、ライブラリ手続きにパラメーター(値または参照)を渡すか、ライブラリ関数から変数(値または参照)を返すと、間接的に共有ライブラリとデータ交換(値により)またはデータ共有(参照により)できます。

主コードと dll コード間で(参照により)データを共有する、Windows での回避策の例(任意のプラットフォームで機能します):
(必要に応じて静的または動的にロード可能な dll)
' dllShareData.bas to be compile with -dll
' Sharing data between main and dll code

' 'Alias' clause (in addition to 'Export') allows compatibility with dll loaded statically or dynamically

' share main variable
Dim Shared ByRef As Integer Idll = *CPtr(Integer Ptr, 0)
Sub passIntByRef Alias"passIntByRef"(ByRef i As Integer) Export
    Print "   dll code receives by reference main integer"
    @Idll = @i
End Sub

Sub printIdll Alias"printIdll"() Export
    Print "   dll code prints its own reference"
    Print "   " & Idll
End Sub

Sub incrementIdll Alias"incrementIdll"() Export
    Idll += 1
End Sub

' share dll variable
Dim Shared As Integer Jdll = 5
Function returnIntByRef Alias"returnIntByRef"() ByRef As Integer Export
    Print "   dll code returns by reference dll integer"
    Return Jdll
End Function

Sub printJdll Alias"printJdll"() Export
    Print "   dll code prints its dll integer"
    Print "   " & Jdll
End Sub

Sub incrementJdll Alias"incrementJdll"() Export
    Jdll +=1
End Sub

' mainShareData.bas
' Sharing data between main and dll code

' 'Alias' clause allows compatibility with dll loaded statically or dynamically

' dll loaded statically
    #inclib "dllShareData"
    Declare Sub passIntByRef Alias"passIntByRef"(ByRef i As Integer)
    Declare Function returnIntByRef Alias"returnIntByRef"() ByRef  As Integer
    Declare Sub printIdll Alias"printIdll"()
    Declare Sub printJdll Alias"printJdll"()
    Declare Sub incrementIdll Alias"incrementIdll"()
    Declare Sub incrementJdll Alias"incrementJdll"()
 ' or dll loaded dynamically
    'Dim As Any Ptr libhandle = DyLibLoad("dllShareData")
    'Dim As Sub(Byref i As Integer) passIntByRef = DyLibSymbol(libhandle, "passIntByRef")
    'Dim As Function() Byref  As Integer returnIntByRef = DyLibSymbol(libhandle, "returnIntByRef")
    'Dim As Sub() printIdll = DyLibSymbol(libhandle, "printIdll")
    'Dim As Sub() printJdll = DyLibSymbol(libhandle, "printJdll")
    'Dim As Sub() incrementIdll = DyLibSymbol(libhandle, "incrementIdll")
    'Dim As Sub() incrementJdll = DyLibSymbol(libhandle, "incrementJdll")

' share main variable
Dim Shared As Integer Imain = 1
Print "main code passes by reference main integer to dll code"
passIntByref(Imain)
Print "main code requests dll code to print its own reference"
printIdll()
Print "main code increments its main integer value"
Imain += 1
Print "main code requests dll code to print its own reference"
printIdll()
Print "main code requests dll to increments its own reference"
incrementIdll()
Print "main code prints its main integer"
Print "" & Imain

Print

' share dll variable
Dim Shared ByRef As Integer Jdll = *CPtr(Integer Ptr, 0)
Print "main code requests by reference dll integer from dll code"
Dim As Integer Ptr pJdll = @(returnIntByRef())
Print "main code receives by reference dll integer"
@Jdll = pJdll
Print "main code prints its own reference"
Print "" & Jdll
Print "main code requests dll to increment its dll integer value"
incrementJdll()
Print "main code prints its own reference"
Print "" & Jdll
Print "main code increments its own reference"
Jdll += 1
Print "main code requests dll code to print its dll integer"
printJdll()
Print

' for dll loaded dynamically
    'DyLibFree(libhandle)

Sleep

主コードと dll コード間でデータを(参照によって返される単一の静的関数によって)共有する、Windows での回避策の簡単な例(任意のプラットフォームで機能):
(必要に応じて静的または動的にロード可能な dll)
' dllShareData2.bas to be compile with -dll
' Sharing data between main and dll code by using static funtion returning by reference

' 'Alias' clause (in addition to 'Export') allows compatibility with dll loaded statically or dynamically

Function returnIntByRef Alias"returnIntByRef"() ByRef As Integer Export
    Static As Integer Jdll = 1
    Return Jdll
End Function

Sub printJdll Alias"printJdll"() Export
    Print "   dll code prints the reference"
    Print "   " & returnIntByRef()
End Sub

Sub incrementJdll Alias"incrementJdll"() Export
    returnIntByRef() +=1
End Sub

' mainShareData2.bas
' Sharing data between main and dll code by using static funtion returning by reference

' 'Alias' clause allows compatibility with dll loaded statically or dynamically

' dll loaded statically
    #inclib "dllShareData2"
    Declare Function returnIntByRef Alias"returnIntByRef"() ByRef  As Integer
    Declare Sub printJdll Alias"printJdll"()
    Declare Sub incrementJdll Alias"incrementJdll"()
 ' or dll loaded dynamically
    'Dim As Any Ptr libhandle = DyLibLoad("dllShareData2")
    'Dim As Function() Byref As Integer returnIntByRef = DyLibSymbol(libhandle, "returnIntByRef")
    'Dim As Sub() printJdll = DyLibSymbol(libhandle, "printJdll")
    'Dim As Sub() incrementJdll = DyLibSymbol(libhandle, "incrementJdll")

Print "main code requests dll code to print the reference"
printJdll()
Print "main code prints the reference"
Print "" & returnIntByRef()
Print
Print "main code requests dll to increment the reference"
incrementJdll()
Print "main code requests dll code to print the reference"
printJdll()
Print "main code prints the reference"
Print "" & returnIntByRef()
Print
Print "main code increments the reference"
returnIntByRef() += 1
Print "main code prints the reference"
Print "" & returnIntByRef()
Print "main code requests dll code to print the reference"
printJdll()
Print

' for dll loaded dynamically
    'DyLibFree(libhandle)

Sleep

このページの頭に戻る

7. Windows での定義ファイルからのインポート ライブラリの作成、または DLL ファイルからのインポート ライブラリまたは定義ファイルの作成
Windows 上の FreeBASIC で、サードパーティの dll を使う場合、リンカを満たすためにインポート ライブラリまたは定義ファイルを手動で構築する必要がある場合があります。

既存の DLL (*.dll) の定義ファイル (*.def) から、Windows 用のインポート ライブラリ ファイル (*.dll.a) を作成する構文:
- 32-bit:
drive:\FreeBASIC\bin\win32\dlltool.exe -d XXX.def -l libXXX.dll.a
- 64-bit:
drive:\FreeBASIC\bin\win64\dlltool.exe -m i386:x86-64 --as-flags --64 -d XXX.def -l libXXX.dll.a

Windows 用のインポート ライブラリ ファイル (*.dll.a) を既存の DLL (*.dll) から直接作成する構文:
- 32-bit:
drive:\FreeBASIC\bin\win32\dlltool -k -d XXX.dll -l libXXX.dll.a
- 64-bit:
drive:\FreeBASIC\bin\win64\dlltool -k -d XXX.dll -l libXXX.dll.a

既存の DLL (*.dll) から Windows 用の定義ファイル (*.def) を作成する構文:
- 32-bit:
drive:\FreeBASIC\bin\win32\dlltool --dllname XXX.dll --output-def XXX.def
- 64-bit:
drive:\FreeBASIC\bin\win64\dlltool --dllname XXX.dll --output-def XXX.def
or using -D and -z:
- 32-bit:
drive:\FreeBASIC\bin\win32\dlltool -D XXX.dll -z XXX.def
- 64-bit:
drive:\FreeBASIC\bin\win64\dlltool -D XXX.dll -z XXX.def

with:
drive:\FreeBASIC\
FreeBASIC installation path
XXX
name of the lib and def file

このページの頭に戻る
参照:
このページの頭に戻る
プログラマーのための案内に戻る
←リンク元に戻る プログラム開発関連に戻る
ページ歴史:2023-02-08 00:10:10
日本語翻訳:WATANABE Makoto、原文著作者:JeffMarshall

ホームページのトップに戻る

表示-非営利-継承